diff --git a/.gitignore b/.gitignore index b6b4a1a559a8..a45e21137561 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/Docs.gmk b/make/Docs.gmk index a8d40e078e2a..9cee8cd40c1b 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -1,4 +1,4 @@ -# 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 @@ -93,19 +93,16 @@ JAVADOC_DISABLED_DOCLINT_WARNINGS := missing JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio # The initial set of options for javadoc -# -XDaccessInternalAPI is a temporary workaround, see 8373909 JAVADOC_OPTIONS := -use -keywords -notimestamp \ -serialwarn -encoding utf-8 -docencoding utf-8 -breakiterator \ -splitIndex --system none -javafx --expand-requires transitive \ - --override-methods=summary \ - -XDaccessInternalAPI + --override-methods=summary # The reference options must stay stable to allow for comparisons across the # development cycle. REFERENCE_OPTIONS := -XDignore.symbol.file=true -use -keywords -notimestamp \ -serialwarn -encoding utf-8 -breakiterator -splitIndex --system none \ - -html5 -javafx --expand-requires transitive \ - -XDaccessInternalAPI + -html5 -javafx --expand-requires transitive # Should we add DRAFT stamps to the generated javadoc? ifeq ($(VERSION_IS_GA), true) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 02ea632e3ec7..d4be5936c411 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -1020,6 +1020,9 @@ define SetupRunJtregTestBody VM_OPTIONS := $$(JTREG_ALL_OPTIONS) )) $$(call LogWarn, AOT_JDK_CACHE=$$($1_AOT_JDK_CACHE)) $1_JTREG_BASIC_OPTIONS += -vmoption:-XX:AOTCache="$$($1_AOT_JDK_CACHE)" + $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-AotJdk.txt) \ + )) endif diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 4b21d481049d..3a5fac345973 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 f41693e05fbb..e8db4888d3af 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/jdk/src/classes/build/tools/taglet/JSpec.java b/make/jdk/src/classes/build/tools/taglet/JSpec.java index 7e1e0ca215e3..196aaccb32b5 100644 --- a/make/jdk/src/classes/build/tools/taglet/JSpec.java +++ b/make/jdk/src/classes/build/tools/taglet/JSpec.java @@ -25,13 +25,13 @@ package build.tools.taglet; +import java.net.URI; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.lang.reflect.Field; import javax.lang.model.element.Element; @@ -141,6 +141,11 @@ public String getName() { @Override public String toString(List tags, Element elem) { + throw new UnsupportedOperationException(); + } + + // @Override - requires JDK-8373922 in build JDK + public String toString(List tags, Element elem, URI docRoot) { if (tags.isEmpty()) return ""; @@ -177,7 +182,7 @@ public String toString(List tags, Element elem) { String preview = m.group("preview"); // null if no preview feature String chapter = m.group("chapter"); String section = m.group("section"); - String rootParent = currentPath().replaceAll("[^/]+", ".."); + String rootParent = docRoot.resolve("..").toString(); String url = preview == null ? String.format("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s", @@ -230,23 +235,6 @@ public String toString(List tags, Element elem) { return sb.toString(); } - private static ThreadLocal CURRENT_PATH = null; - - private String currentPath() { - if (CURRENT_PATH == null) { - try { - Field f = Class.forName("jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter") - .getField("CURRENT_PATH"); - @SuppressWarnings("unchecked") - ThreadLocal tl = (ThreadLocal) f.get(null); - CURRENT_PATH = tl; - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Cannot determine current path", e); - } - } - return CURRENT_PATH.get(); - } - private String expand(List trees) { return (new SimpleDocTreeVisitor() { public StringBuilder defaultAction(DocTree tree, StringBuilder sb) { diff --git a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java index 2ffd92e34094..300999b77c05 100644 --- a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java +++ b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java @@ -32,7 +32,9 @@ import javax.lang.model.element.*; import javax.lang.model.type.DeclaredType; +import javax.lang.model.util.Elements; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -78,6 +80,11 @@ public void init(DocletEnvironment env, Doclet doclet) { @Override public String toString(List tags, Element element) { + throw new UnsupportedOperationException(); + } + + // @Override - requires JDK-8373922 in build JDK + public String toString(List tags, Element element, URI docRoot) { if (sealedDotOutputDir == null || sealedDotOutputDir.isEmpty()) { return ""; } @@ -85,9 +92,15 @@ public String toString(List tags, Element element) { return ""; } - ModuleElement module = docletEnvironment.getElementUtils().getModuleOf(element); + Elements util = docletEnvironment.getElementUtils(); + ModuleElement module = util.getModuleOf(element); + + // '.' in .DOT file name is converted to '/' in .SVG path, so we use '-' as separator for nested classes. + // module_package.subpackage.Outer-Inner.dot => module/package/subpackage/Outer-Inner-sealed-graph.svg Path dotFile = Path.of(sealedDotOutputDir, - module.getQualifiedName() + "_" + typeElement.getQualifiedName() + ".dot"); + module.getQualifiedName() + "_" + + util.getPackageOf(element).getQualifiedName() + "." + + packagelessCanonicalName(typeElement).replace(".", "-") + ".dot"); Set exports = module.getDirectives().stream() .filter(ModuleElement.ExportsDirective.class::isInstance) @@ -99,7 +112,7 @@ public String toString(List tags, Element element) { .map(Objects::toString) .collect(Collectors.toUnmodifiableSet()); - String dotContent = new Renderer().graph(typeElement, exports); + String dotContent = new Renderer().graph(typeElement, exports, docRoot); try { Files.writeString(dotFile, dotContent, WRITE, CREATE, TRUNCATE_EXISTING); @@ -107,8 +120,8 @@ public String toString(List tags, Element element) { throw new RuntimeException(e); } - String simpleTypeName = packagelessCanonicalName(typeElement).replace('.', '/'); - String imageFile = simpleTypeName + "-sealed-graph.svg"; + String simpleTypeName = packagelessCanonicalName(typeElement); + String imageFile = simpleTypeName.replace(".", "-") + "-sealed-graph.svg"; int thumbnailHeight = 100; // also appears in the stylesheet String hoverImage = "" + getImage(simpleTypeName, imageFile, -1, true) @@ -137,12 +150,12 @@ private String getImage(String typeName, String file, int height, boolean useBor private final class Renderer { // Generates a graph in DOT format - String graph(TypeElement rootClass, Set exports) { + String graph(TypeElement rootClass, Set exports, URI pathToRoot) { if (!isInPublicApi(rootClass, exports)) { // Alternatively we can return "" for the graph since there is no single root to render throw new IllegalArgumentException("Root not in public API: " + rootClass.getQualifiedName()); } - final State state = new State(rootClass); + final State state = new State(pathToRoot); traverse(state, rootClass, exports); return state.render(); } @@ -168,7 +181,7 @@ private final class State { private static final String TOOLTIP = "tooltip"; private static final String LINK = "href"; - private final TypeElement rootNode; + private final URI pathToRoot; private final StringBuilder builder; @@ -193,8 +206,8 @@ public String valueString() { } } - public State(TypeElement rootNode) { - this.rootNode = rootNode; + public State(URI pathToRoot) { + this.pathToRoot = pathToRoot; nodeStyleMap = new LinkedHashMap<>(); builder = new StringBuilder() .append("digraph G {") @@ -217,24 +230,15 @@ public void addNode(TypeElement node) { var styles = nodeStyleMap.computeIfAbsent(id(node), n -> new LinkedHashMap<>()); styles.put(LABEL, new StyleItem.PlainString(node.getSimpleName().toString())); styles.put(TOOLTIP, new StyleItem.PlainString(node.getQualifiedName().toString())); - styles.put(LINK, new StyleItem.PlainString(relativeLink(node))); + styles.put(LINK, new StyleItem.PlainString(pathToRoot.resolve(relativeLink(node)).toString())); } - // A permitted class must be in the same package or in the same module. - // This implies the module is always the same. private String relativeLink(TypeElement node) { var util = SealedGraph.this.docletEnvironment.getElementUtils(); - var nodePackage = util.getPackageOf(node); - // Note: SVG files for nested types use the simple names of containing types as parent directories. - // We therefore need to convert all dots in the qualified name to "../" below. - var backNavigator = rootNode.getQualifiedName().toString().chars() - .filter(c -> c == '.') - .mapToObj(c -> "../") - .collect(joining()); - var forwardNavigator = nodePackage.getQualifiedName().toString() - .replace(".", "/"); - - return backNavigator + forwardNavigator + "/" + packagelessCanonicalName(node) + ".html"; + var path = util.getModuleOf(node).getQualifiedName().toString() + "/" + + util.getPackageOf(node).getQualifiedName().toString().replace(".", "/"); + + return path + "/" + packagelessCanonicalName(node) + ".html"; } public void addEdge(TypeElement node, TypeElement subNode) { @@ -286,14 +290,6 @@ private String id(TypeElement node) { private String quotedId(TypeElement node) { return "\"" + id(node) + "\""; } - - private String simpleName(String name) { - int lastDot = name.lastIndexOf('.'); - return lastDot < 0 - ? name - : name.substring(lastDot); - } - } private static List permittedSubclasses(TypeElement node, Set exports) { diff --git a/make/jdk/src/classes/build/tools/taglet/ToolGuide.java b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java index 8db2aee30928..7ad4f6b9b9f6 100644 --- a/make/jdk/src/classes/build/tools/taglet/ToolGuide.java +++ b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, 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 @@ -25,13 +25,13 @@ package build.tools.taglet; +import java.net.URI; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.lang.reflect.Field; import javax.lang.model.element.Element; @@ -91,6 +91,11 @@ public String getName() { @Override public String toString(List tags, Element elem) { + throw new UnsupportedOperationException(); + } + + // @Override - requires JDK-8373922 in build JDK + public String toString(List tags, Element elem, URI docRoot) { if (tags.isEmpty()) return ""; @@ -118,7 +123,7 @@ public String toString(List tags, Element elem) { if (label.isEmpty()) { label = name; } - String rootParent = currentPath().replaceAll("[^/]+", ".."); + String rootParent = docRoot.resolve("..").toString(); String url = String.format("%s/%s/%s.html", rootParent, BASE_URL, name); @@ -141,22 +146,4 @@ public String toString(List tags, Element elem) { return sb.toString(); } - - private static ThreadLocal CURRENT_PATH = null; - - private String currentPath() { - if (CURRENT_PATH == null) { - try { - Field f = Class.forName("jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter") - .getField("CURRENT_PATH"); - @SuppressWarnings("unchecked") - ThreadLocal tl = (ThreadLocal) f.get(null); - CURRENT_PATH = tl; - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Cannot determine current path", e); - } - } - return CURRENT_PATH.get(); - } - } diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 3e37fe796435..2326505d11c2 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/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 53fa4e3066c7..185d5b720133 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 58ed234194ab..ebf73813715a 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 4c1c8d9bbc80..c8d5ee2eaeb8 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 @@ class Assembler : public AbstractAssembler { 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 4de6237304d0..4eb4e3d5ac7e 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()); - } +void LIR_Assembler::load_volatile(LIR_Address *from_addr, LIR_Opr dest, + BasicType type, CodeEmitInfo* info) { + __ lea(rscratch1, as_Address(from_addr)); - __ verify_oop(dest->as_register()); + 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 5af06fc6a1c6..367256d2f696 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 f10c5197d911..7e82f410a950 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/shared/cardTableBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp index a9c320912cb7..7ce4e0f8aed2 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp @@ -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 @@ -56,7 +56,7 @@ void CardTableBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet d } } -void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst, Register tmp1, Register tmp2) { +void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2) { precond(tmp1 != noreg); precond(tmp2 != noreg); assert_different_registers(obj, tmp1, tmp2); @@ -114,10 +114,10 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS if (needs_post_barrier) { // flatten object address if needed if (!precise || (dst.index() == noreg && dst.offset() == 0)) { - store_check(masm, dst.base(), dst, tmp1, tmp2); + store_check(masm, dst.base(), tmp1, tmp2); } else { __ lea(tmp3, dst); - store_check(masm, tmp3, dst, tmp1, tmp2); + store_check(masm, tmp3, tmp1, tmp2); } } } diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp index e05e9e90e5d8..07016381f788 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp @@ -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 @@ -46,7 +46,7 @@ class CardTableBarrierSetAssembler: public BarrierSetAssembler { virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); - void store_check(MacroAssembler* masm, Register obj, Address dst, Register tmp1, Register tmp2); + void store_check(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2); }; #endif // CPU_AARCH64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_AARCH64_HPP 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 e4db8a9ab1f8..e31a58243b5a 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 7bec0a3c0caf..40f7251600aa 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 a6cc862d05ca..e5e36d435164 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 @@ class MacroAssembler: public Assembler { // 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 69769fb84414..4c64b265d929 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/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 60a0ef307b5b..45ae283e05a2 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 4c339968f851..46ec87290ae3 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 5f030676bcb3..a652a155f62b 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/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index f3d33b4305d2..33747538e006 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -12480,6 +12480,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 +12649,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); diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index f290708a231b..5e0deb84a14e 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 0d06fd469de8..c9cd8220551b 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 fa87ceba2952..468d53b1a540 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/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 5cc725e3af40..bae5bb7b57b3 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 5a0fd5f95615..1ffd172df8f0 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/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index f448e4ee17fe..cc068cda7a9b 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/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 1de147926bb9..c05f37a3bea2 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -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 @@ -130,7 +130,7 @@ __ BIND(L_loop); __ BIND(L_done); } -void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst, Register rscratch) { +void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register rscratch) { // Does a store check for the oop in register obj. The content of // register obj is destroyed afterwards. CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); @@ -192,10 +192,10 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS if (needs_post_barrier) { // flatten object address if needed if (!precise || (dst.index() == noreg && dst.disp() == 0)) { - store_check(masm, dst.base(), dst, tmp2); + store_check(masm, dst.base(), tmp2); } else { __ lea(tmp1, dst); - store_check(masm, tmp1, dst, tmp2); + store_check(masm, tmp1, tmp2); } } } diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp index 201c11062f28..c38e16d4d5fe 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp @@ -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 @@ -33,7 +33,7 @@ class CardTableBarrierSetAssembler: public BarrierSetAssembler { virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) {} - void store_check(MacroAssembler* masm, Register obj, Address dst, Register rscratch); + void store_check(MacroAssembler* masm, Register obj, Register rscratch); virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 5ab3ca339aa6..4c851377ce5d 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); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 021d2943ee8b..b73339c217f6 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/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index cf9de40a2370..7d9ceb9d4460 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -2527,7 +2527,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; } } diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index eaa88d900c7a..b892c4c9a01a 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -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 ); %} @@ -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 3cad24d388ce..32d845b2b6d0 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 cbf78083483e..3668ac6ba3ff 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 a4d9a2197a54..4c77b619718d 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -444,14 +444,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 +538,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 +550,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 diff --git a/src/hotspot/os/bsd/os_perf_bsd.cpp b/src/hotspot/os/bsd/os_perf_bsd.cpp index 78d9519c3a71..47fe3a0d7e99 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 4a2d75ecdf3b..1c183a9bbab5 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 f166f6cd5e47..1f7775acfc30 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 68585c22c2db..c5df7e8efa9f 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 da2cbf381e6c..511c7bebff76 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 a87c0ab33fa1..6927f5108acc 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 9f91f3b4c0d2..c0e863ed2a2f 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 0663cae61f37..00675683e349 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 c5046797e02d..300c86ffc47a 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 9d04ae65954c..59ea83b91488 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 9d8fb45f0d1f..9a987bf3762c 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 dad2804f18ac..8e698c53d283 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/windows_aarch64/sve_windows_aarch64.S b/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S index e0c85830bd42..137cd0f7753d 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 e78a37b41782..e485ae6b8c27 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 854cf73049bf..c64750505927 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 ec0ea5dc047d..8e30d05af6db 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/aotStreamedHeapLoader.cpp b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp index 39f735543cde..7f9f8cf06286 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 21eef3d7b0bb..cf51897c2f15 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 ecf3c6d2231c..21066f76932a 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 447914b31013..7df498ca5b90 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 8e1f298e8e31..c90e233df737 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 38502b2b2d84..1ed9979ff856 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -402,7 +402,7 @@ class FileHeaderHelper { ~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/cds/lambdaProxyClassDictionary.hpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp index dfb75532917c..b20e998bba62 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP -#define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP +#ifndef SHARE_CDS_LAMBDAPROXYCLASSDICTIONARY_HPP +#define SHARE_CDS_LAMBDAPROXYCLASSDICTIONARY_HPP #include "cds/aotCompressedPointers.hpp" #include "cds/aotMetaspace.hpp" @@ -331,4 +331,4 @@ class LambdaProxyClassDictionary : public OffsetCompactHashtable< static void print_statistics(outputStream* st, bool is_static_archive); }; -#endif // SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP +#endif // SHARE_CDS_LAMBDAPROXYCLASSDICTIONARY_HPP diff --git a/src/hotspot/share/ci/ciMethodData.cpp b/src/hotspot/share/ci/ciMethodData.cpp index 533e86599682..5e623e2b9655 100644 --- a/src/hotspot/share/ci/ciMethodData.cpp +++ b/src/hotspot/share/ci/ciMethodData.cpp @@ -537,8 +537,8 @@ void ciMethodData::clear_escape_info() { if (mdo != nullptr) { mdo->clear_escape_info(); ArgInfoData *aid = arg_info(); - int arg_count = (aid == nullptr) ? 0 : aid->number_of_args(); - for (int i = 0; i < arg_count; i++) { + int arg_size = (aid == nullptr) ? 0 : aid->size_of_args(); + for (int i = 0; i < arg_size; i++) { set_arg_modified(i, 0); } } @@ -554,8 +554,8 @@ void ciMethodData::update_escape_info() { mdo->set_arg_local(_arg_local); mdo->set_arg_stack(_arg_stack); mdo->set_arg_returned(_arg_returned); - int arg_count = mdo->method()->size_of_parameters(); - for (int i = 0; i < arg_count; i++) { + int arg_size = mdo->method()->size_of_parameters(); + for (int i = 0; i < arg_size; i++) { mdo->set_arg_modified(i, arg_modified(i)); } } @@ -652,7 +652,7 @@ void ciMethodData::set_arg_modified(int arg, uint val) { ArgInfoData *aid = arg_info(); if (aid == nullptr) return; - assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); + assert(arg >= 0 && arg < aid->size_of_args(), "valid argument number"); aid->set_arg_modified(arg, val); } @@ -672,7 +672,7 @@ uint ciMethodData::arg_modified(int arg) const { ArgInfoData *aid = arg_info(); if (aid == nullptr) return 0; - assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); + assert(arg >= 0 && arg < aid->size_of_args(), "valid argument number"); return aid->arg_modified(arg); } diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 6266c024260f..35522e75877b 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 a9ea6fbea119..d5ee16fec320 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 eced83577cb8..6d25e460688d 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 de67971c4033..f06f1986d8b7 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 c41d5d2f0528..958d4812cbbc 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/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index c2838917516d..736f0ac984b5 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -652,6 +652,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 +670,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 +888,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 +909,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 +925,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 +1024,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 +1057,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 +1124,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 +1160,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 +1332,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 +1456,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 +1584,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 +1669,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 +1742,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 +1758,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 +1769,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 +1800,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 +1815,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 +1842,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++) { @@ -2184,7 +2209,7 @@ void AOTCodeAddressTable::set_stubgen_stubs_complete() { #ifdef PRODUCT #define MAX_STR_COUNT 200 #else -#define MAX_STR_COUNT 500 +#define MAX_STR_COUNT 2000 #endif #define _c_str_max MAX_STR_COUNT static const int _c_str_base = _all_max; @@ -2296,7 +2321,7 @@ const char* AOTCodeAddressTable::add_C_string(const char* str) { int AOTCodeAddressTable::id_for_C_string(address str) { if (str == nullptr) { - return -1; + return BAD_ADDRESS_ID; } MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag); for (int i = 0; i < _C_strings_count; i++) { @@ -2314,7 +2339,7 @@ int AOTCodeAddressTable::id_for_C_string(address str) { return id; } } - return -1; + return BAD_ADDRESS_ID; } address AOTCodeAddressTable::address_for_C_string(int idx) { @@ -2381,13 +2406,13 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB } // Seach for C string id = id_for_C_string(addr); - if (id >= 0) { + if (id != BAD_ADDRESS_ID) { return id + _c_str_base; } if (StubRoutines::contains(addr) || CodeCache::find_blob(addr) != nullptr) { // Search for a matching stub entry id = search_address(addr, _stubs_addr, _stubs_max); - if (id < 0) { + if (id == BAD_ADDRESS_ID) { StubCodeDesc* desc = StubCodeDesc::desc_for(addr); if (desc == nullptr) { desc = StubCodeDesc::desc_for(addr + frame::pc_return_offset); @@ -2400,7 +2425,7 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB } else { // Search in runtime functions id = search_address(addr, _extrs_addr, _extrs_length); - if (id < 0) { + if (id == BAD_ADDRESS_ID) { ResourceMark rm; const int buflen = 1024; char* func_name = NEW_RESOURCE_ARRAY(char, buflen); diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 5b773a986f19..296464533f0e 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -252,7 +252,7 @@ class AOTStubData : public StackObj { 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 @@ class AOTCodeCache : public CHeapObj { 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 @@ class AOTCodeReader { 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.hpp b/src/hotspot/share/code/codeBlob.hpp index d372e72fc23d..709623de3085 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -226,7 +226,7 @@ class CodeBlob { nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } CodeBlob* as_codeblob() const { return (CodeBlob*) this; } // we may want to force an actual buffer blob or subtype instance - BufferBlob* as_buffer_blob(bool strict = true) const { assert(is_buffer_blob(), "must be %sbuffer blob", (strict ? "strict " : "")); return (BufferBlob*) this; } + BufferBlob* as_buffer_blob(bool strict = true) const { assert(is_buffer_blob(strict), "must be %sbuffer blob", (strict ? "strict " : "")); return (BufferBlob*) this; } AdapterBlob* as_adapter_blob() const { assert(is_adapter_blob(), "must be adapter blob"); return (AdapterBlob*) this; } ExceptionBlob* as_exception_blob() const { assert(is_exception_stub(), "must be exception stub"); return (ExceptionBlob*) this; } // this will always return a subtype instance diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index c0b4918102ed..2aaa061dca3a 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 a295d1271aa6..f0ad9921cd09 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 261658e04eb1..5a9c124688e5 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 1951fd066fc4..82bd4c160d29 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -487,7 +487,7 @@ class MemStatEntry : public CHeapObj { 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 7b236ed35893..2ae6a5f67f4b 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(); } @@ -2402,7 +2404,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 +2412,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 +2612,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 d0ea80d60194..d0833fbe7faf 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 536d81045d7d..5b01105c707d 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 (after_compile_details) { + sst.print("%s", method->name_and_sig_as_C_string(true /* use_double_colon */)); + } else { + method->print_short_name(&sst); + } if (is_osr_method) { - st->print(" @ %d", osr_bci); + sst.print(" @ %d", osr_bci); } - if (method->is_native()) - st->print(" (native)"); - else - st->print(" (%d bytes)", method->code_size()); + 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 2cc5e9afe3c3..d7324f71ea50 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -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 @@ class CompileTask : public CHeapObj { 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); diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 1cd8bd1b5106..d0042d0e16cd 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 e4826b3056c8..d9b229353ecc 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 665f3b2fbfd9..5615a2cf1fcd 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 a2da7c7e0e4c..53a8325702e6 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 87467d064008..c8d0c5d22ba4 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 213fc18b8fff..7ec4a0016dbe 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -70,7 +70,7 @@ class EpsilonSpaceCounters: public CHeapObj { } ~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 34d31702e80c..3bf26bf46c92 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 601d0f1138ea..e8a0e797dfa5 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp @@ -74,7 +74,7 @@ class G1BarrierSetC2: public CardTableBarrierSetC2 { 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 78710084ee37..e9d1c13af7a0 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 c3bbd5a3b527..a0acd903b0f9 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 60ad63e812c0..f0db638a2fed 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 0da2f90da3f3..95a32bae7668 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 d8cabaa00a46..27b41ef165ff 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 2709e6b30087..de0a0927115d 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 3a47453819e6..a68d10306365 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1032,7 +1032,7 @@ class G1CollectedHeap : public CollectedHeap { // 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 b3bcf6094abc..7329e679519e 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 @@ class G1VerifyYoungCSetIndicesClosure : public G1HeapRegionClosure { } } ~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 2113db1163ba..3637d4772297 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 dbb5ba509a2c..d5e3b9cc69d1 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) { @@ -676,9 +676,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 ce944f2254d3..e522163f9806 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 37553e2aa561..03c20346eb35 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 c835dd159a69..8b38509d1d81 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 023790a24223..e13b9d91bc52 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 b57bf0d617ed..eb51b340da3c 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/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 3c0318827efc..214f1a2d2b6c 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 @@ class G1RebuildFreeListTask : public WorkerTask { 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 70186adcdfce..930a4bd953f7 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 30ad4c72bf66..690bda4e7e6a 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/g1IHOPControl.cpp b/src/hotspot/share/gc/g1/g1IHOPControl.cpp index 1e1c52477f9a..164486123f77 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 ff209012f024..2836408978b3 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 3f97870a67f5..aea6f4335e8c 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 922c68bfba4a..c12321b851aa 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 778ed31d7b54..db42b8c10fc4 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 aaebfa1be8f3..ce62d34f8479 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 52c8d4d43895..50438c641c2b 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 78a533d62c02..769977c7dacf 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 5c5c2bc35725..0aa15be9caec 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -296,7 +296,7 @@ class G1Policy: public CHeapObj { 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 c5f55e1d20c5..a9f4115df949 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 c1c0d471796e..9550e57698ee 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 9f9f0ecdf3a5..be18a3065e9e 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 @@ class G1ClearCardTableTask : public G1AbstractSubTask { _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 3e9cf9380970..1c0e15757cc3 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 f858b93b13d4..15c6d3d1f15a 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 14282383e296..11da3cb82631 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -802,7 +802,7 @@ class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1 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 936457659b61..7889fd4fb31e 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp @@ -73,7 +73,7 @@ class G1PreEvacuateCollectionSetBatchTask::JavaThreadRetireTLABs : public G1Abst ~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/jvmFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp index b56e82fac3c0..df6adeb80417 100644 --- a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp @@ -70,7 +70,7 @@ JVMFlag::Error G1RemSetHowlMaxNumBucketsConstraintFunc(uint value, bool verbose) } if (!is_power_of_2(G1RemSetHowlMaxNumBuckets)) { JVMFlag::printError(verbose, - "G1RemSetMaxHowlNumBuckets (%u) must be a power of two.\n", + "G1RemSetHowlMaxNumBuckets (%u) must be a power of two.\n", value); return JVMFlag::VIOLATES_CONSTRAINT; } diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index c5d112ffbc11..8b514fe71991 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 90e50f52e84a..855f872afab2 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 a31078f7e679..692893544d53 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 4eac2561e679..d2b4a2fc636d 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 f01997f98547..1624c6934707 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 c91029441974..1ff6fd493a76 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 f6bbc1c26185..85da4c99cbb4 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 a873bc2f45c5..5dd9d5bfaa85 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 21e63f6fc321..8aea565cdf74 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 d3b21c2fdaa0..4679ac2f51c3 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 605b7afe0729..6a69fe10f951 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 b3f96da1cce4..ab1b15b04478 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 a376f3b96dec..546efa4774bd 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 b142aadc5802..c942b6cc3e99 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 f9b8694eb042..59d7befb32de 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 34549bc079e0..3b7658ec4c8e 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 1826b9d7df8b..736a9b007dd0 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 f721c3cd001b..4fcc90d7bde3 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 108eaa0998bf..c77a9da63fc1 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 6b327d7e4af9..65e255011fbb 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() { @@ -209,14 +209,14 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand } } -void ShenandoahAdaptiveHeuristics::add_degenerated_gc_time(double timestamp, double gc_time) { +void ShenandoahAdaptiveHeuristics::add_degenerated_gc_time(double time_at_start, double gc_time) { // Conservatively add sample into linear model If this time is above the predicted concurrent gc time - if (predict_gc_time(timestamp) < gc_time) { - add_gc_time(timestamp, gc_time); + if (predict_gc_time(time_at_start) < gc_time) { + add_gc_time(time_at_start, gc_time); } } -void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time) { +void ShenandoahAdaptiveHeuristics::add_gc_time(double time_at_start, double gc_time) { // Update best-fit linear predictor of GC time uint index = (_gc_time_first_sample_index + _gc_time_num_samples) % GC_TIME_SAMPLE_SIZE; if (_gc_time_num_samples == GC_TIME_SAMPLE_SIZE) { @@ -225,10 +225,10 @@ void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time) _gc_time_sum_of_xy -= _gc_time_xy[index]; _gc_time_sum_of_xx -= _gc_time_xx[index]; } - _gc_time_timestamps[index] = timestamp; + _gc_time_timestamps[index] = time_at_start; _gc_time_samples[index] = gc_time; - _gc_time_xy[index] = timestamp * gc_time; - _gc_time_xx[index] = timestamp * timestamp; + _gc_time_xy[index] = time_at_start * gc_time; + _gc_time_xx[index] = time_at_start * time_at_start; _gc_time_sum_of_timestamps += _gc_time_timestamps[index]; _gc_time_sum_of_samples += _gc_time_samples[index]; @@ -247,18 +247,26 @@ void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time) _gc_time_b = gc_time; _gc_time_sd = 0.0; } else if (_gc_time_num_samples == 2) { + + assert(time_at_start > _gc_time_timestamps[_gc_time_first_sample_index], + "Two GC cycles cannot finish at same time: %.6f vs %.6f, with GC times %.6f and %.6f", time_at_start, + _gc_time_timestamps[_gc_time_first_sample_index], gc_time, _gc_time_samples[_gc_time_first_sample_index]); + // Two points define a line + double delta_x = time_at_start - _gc_time_timestamps[_gc_time_first_sample_index]; double delta_y = gc_time - _gc_time_samples[_gc_time_first_sample_index]; - double delta_x = timestamp - _gc_time_timestamps[_gc_time_first_sample_index]; _gc_time_m = delta_y / delta_x; - // y = mx + b // so b = y0 - mx0 - _gc_time_b = gc_time - _gc_time_m * timestamp; + _gc_time_b = gc_time - _gc_time_m * time_at_start; _gc_time_sd = 0.0; } else { + // Since timestamps are monotonically increasing, denominator does not equal zero. + double denominator = _gc_time_num_samples * _gc_time_sum_of_xx - _gc_time_sum_of_timestamps * _gc_time_sum_of_timestamps; + assert(denominator != 0.0, "Invariant: samples: %u, sum_of_xx: %.6f, sum_of_timestamps: %.6f", + _gc_time_num_samples, _gc_time_sum_of_xx, _gc_time_sum_of_timestamps); _gc_time_m = ((_gc_time_num_samples * _gc_time_sum_of_xy - _gc_time_sum_of_timestamps * _gc_time_sum_of_samples) / - (_gc_time_num_samples * _gc_time_sum_of_xx - _gc_time_sum_of_timestamps * _gc_time_sum_of_timestamps)); + denominator); _gc_time_b = (_gc_time_sum_of_samples - _gc_time_m * _gc_time_sum_of_timestamps) / _gc_time_num_samples; double sum_of_squared_deviations = 0.0; for (size_t i = 0; i < _gc_time_num_samples; i++) { @@ -829,19 +837,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) { @@ -890,9 +908,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/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 3091b19b6003..d2010d921b19 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/mode/shenandoahPassiveMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp index 41b2703730bd..cc098bc5a212 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp @@ -50,7 +50,6 @@ void ShenandoahPassiveMode::initialize_flags() const { SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahSATBBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCASBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCloneBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStackWatermarkBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCardBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp index 7ac2d7b818f7..e27aa90542db 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp @@ -42,6 +42,5 @@ void ShenandoahSATBMode::initialize_flags() const { SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahStackWatermarkBarrier); SHENANDOAH_CHECK_FLAG_UNSET(ShenandoahCardBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index a81efa99d709..4989c929b321 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/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index cb6ff795c07b..0949959b0421 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -149,11 +149,9 @@ void ShenandoahBarrierSet::on_thread_attach(Thread *thread) { BarrierSetNMethod* bs_nm = barrier_set_nmethod(); thread->set_nmethod_disarmed_guard_value(bs_nm->disarmed_guard_value()); - if (ShenandoahStackWatermarkBarrier) { - JavaThread* const jt = JavaThread::cast(thread); - StackWatermark* const watermark = new ShenandoahStackWatermark(jt); - StackWatermarkSet::add_watermark(jt, watermark); - } + JavaThread* const jt = JavaThread::cast(thread); + StackWatermark* const watermark = new ShenandoahStackWatermark(jt); + StackWatermarkSet::add_watermark(jt, watermark); } } @@ -172,14 +170,12 @@ void ShenandoahBarrierSet::on_thread_detach(Thread *thread) { } // SATB protocol requires to keep alive reachable oops from roots at the beginning of GC - if (ShenandoahStackWatermarkBarrier) { - if (_heap->is_concurrent_mark_in_progress()) { - ShenandoahKeepAliveClosure oops; - StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); - } else if (_heap->is_concurrent_weak_root_in_progress() && _heap->is_evacuation_in_progress()) { - ShenandoahContextEvacuateUpdateRootsClosure oops; - StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); - } + if (_heap->is_concurrent_mark_in_progress()) { + ShenandoahKeepAliveClosure oops; + StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); + } else if (_heap->is_concurrent_weak_root_in_progress() && _heap->is_evacuation_in_progress()) { + ShenandoahContextEvacuateUpdateRootsClosure oops; + StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index e7a0ed577408..06e16af24c6f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -96,7 +96,6 @@ class ShenandoahBarrierSet: public BarrierSet { 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 @@ class ShenandoahBarrierSet: public BarrierSet { 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 f4b35e29b09e..97e2af1714d8 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"); + + 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 = resolve_forwarded_not_null_mutator(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/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index fefed0340c48..9ab45380c614 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -180,9 +180,6 @@ class ShenandoahCleanUpdateWeakOopsClosure : public OopClosure { }; class ShenandoahNMethodAndDisarmClosure : public NMethodToOopClosure { -private: - BarrierSetNMethod* const _bs; - public: inline ShenandoahNMethodAndDisarmClosure(OopClosure* cl); inline void do_nmethod(nmethod* nm); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index e8d25b1e5a97..96ecbad1145a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -209,15 +209,13 @@ void ShenandoahCleanUpdateWeakOopsClosure::do_oo } ShenandoahNMethodAndDisarmClosure::ShenandoahNMethodAndDisarmClosure(OopClosure* cl) : - NMethodToOopClosure(cl, true /* fix_relocations */), - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { -} + NMethodToOopClosure(cl, true /* fix_relocations */) {} void ShenandoahNMethodAndDisarmClosure::do_nmethod(nmethod* nm) { assert(nm != nullptr, "Sanity"); assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); NMethodToOopClosure::do_nmethod(nm); - _bs->disarm(nm); + ShenandoahNMethod::disarm_nmethod(nm); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index 64e135e9a4e3..7cf60cdf65cc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -40,20 +40,6 @@ ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table; int ShenandoahCodeRoots::_disarmed_value = 1; -bool ShenandoahCodeRoots::use_nmethod_barriers_for_mark() { - // Continuations need nmethod barriers for scanning stack chunk nmethods. - if (Continuations::enabled()) return true; - - // Concurrent class unloading needs nmethod barriers. - // When a nmethod is about to be executed, we need to make sure that all its - // metadata are marked. The alternative is to remark thread roots at final mark - // pause, which would cause latency issues. - if (ShenandoahHeap::heap()->unload_classes()) return true; - - // Otherwise, we can go without nmethod barriers. - return false; -} - void ShenandoahCodeRoots::initialize() { _nmethod_table = new ShenandoahNMethodTable(); } @@ -68,27 +54,14 @@ void ShenandoahCodeRoots::unregister_nmethod(nmethod* nm) { _nmethod_table->unregister_nmethod(nm); } -void ShenandoahCodeRoots::arm_nmethods_for_mark() { - if (use_nmethod_barriers_for_mark()) { - BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); - } -} - -void ShenandoahCodeRoots::arm_nmethods_for_evac() { +void ShenandoahCodeRoots::arm_nmethods() { BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); } class ShenandoahDisarmNMethodClosure : public NMethodClosure { -private: - BarrierSetNMethod* const _bs; - public: - ShenandoahDisarmNMethodClosure() : - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { - } - virtual void do_nmethod(nmethod* nm) { - _bs->disarm(nm); + ShenandoahNMethod::disarm_nmethod(nm); } }; @@ -111,10 +84,8 @@ class ShenandoahDisarmNMethodsTask : public WorkerTask { }; void ShenandoahCodeRoots::disarm_nmethods() { - if (use_nmethod_barriers_for_mark()) { - ShenandoahDisarmNMethodsTask task; - ShenandoahHeap::heap()->workers()->run_task(&task); - } + ShenandoahDisarmNMethodsTask task; + ShenandoahHeap::heap()->workers()->run_task(&task); } class ShenandoahNMethodUnlinkClosure : public NMethodClosure { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index d29c446f2102..d395b4516f4f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -67,14 +67,11 @@ class ShenandoahCodeRoots : public AllStatic { // Concurrent nmethod unloading support static void unlink(WorkerThreads* workers, bool unloading_occurred); static void purge(); - static void arm_nmethods_for_mark(); - static void arm_nmethods_for_evac(); + static void arm_nmethods(); static void disarm_nmethods(); static int disarmed_value() { return _disarmed_value; } static int* disarmed_value_address() { return &_disarmed_value; } - static bool use_nmethod_barriers_for_mark(); - private: static ShenandoahNMethodTable* _nmethod_table; static int _disarmed_value; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp index bbd9dca15132..cfa79fc055e1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp @@ -257,10 +257,10 @@ void ShenandoahCollectorPolicy::print_gc_stats(outputStream* out) const { out->print_cr("%5zu Full GCs (%.2f%%)", _success_full_gcs, percent_of(_success_full_gcs, completed_gcs)); if (!ExplicitGCInvokesConcurrent) { - out->print_cr(" %5zu invoked explicitly (%.2f%%)", explicit_requests, percent_of(explicit_requests, _success_concurrent_gcs)); + out->print_cr(" %5zu invoked explicitly (%.2f%%)", explicit_requests, percent_of(explicit_requests, _success_full_gcs)); } if (!ShenandoahImplicitGCInvokesConcurrent) { - out->print_cr(" %5zu invoked implicitly (%.2f%%)", implicit_requests, percent_of(implicit_requests, _success_concurrent_gcs)); + out->print_cr(" %5zu invoked implicitly (%.2f%%)", implicit_requests, percent_of(implicit_requests, _success_full_gcs)); } out->print_cr(" %5zu caused by allocation failure (%.2f%%)", _alloc_failure_full, percent_of(_alloc_failure_full, _success_full_gcs)); out->print_cr(" %5zu upgraded from Degenerated GC (%.2f%%)", _alloc_failure_degenerated_upgrade_to_full, percent_of(_alloc_failure_degenerated_upgrade_to_full, _success_full_gcs)); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index ba0aa1a13045..6723bb890213 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -255,8 +255,10 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { return false; } - if (VerifyAfterGC) { - vmop_entry_verify_final_roots(); + // In normal cycle, final-update-refs would verify at the end of the cycle. + // In abbreviated cycle, we need to verify separately. + if (ShenandoahVerify) { + vmop_entry_final_verify(); } } @@ -344,14 +346,14 @@ void ShenandoahConcurrentGC::vmop_entry_final_update_refs() { VMThread::execute(&op); } -void ShenandoahConcurrentGC::vmop_entry_verify_final_roots() { +void ShenandoahConcurrentGC::vmop_entry_final_verify() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters()); - ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_roots_gross); + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_verify_gross); // This phase does not use workers, no need for setup heap->try_inject_alloc_failure(); - VM_ShenandoahFinalRoots op(this); + VM_ShenandoahFinalVerify op(this); VMThread::execute(&op); } @@ -400,12 +402,12 @@ void ShenandoahConcurrentGC::entry_final_update_refs() { op_final_update_refs(); } -void ShenandoahConcurrentGC::entry_verify_final_roots() { - const char* msg = verify_final_roots_event_message(); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_roots); +void ShenandoahConcurrentGC::entry_final_verify() { + const char* msg = verify_final_event_message(); + ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_verify); EventMark em("%s", msg); - op_verify_final_roots(); + op_verify_final(); } void ShenandoahConcurrentGC::entry_reset() { @@ -744,9 +746,8 @@ void ShenandoahConcurrentGC::op_init_mark() { // Make above changes visible to worker threads OrderAccess::fence(); - // Arm nmethods for concurrent mark - ShenandoahCodeRoots::arm_nmethods_for_mark(); - + // Arm nmethods/stack for concurrent processing + ShenandoahCodeRoots::arm_nmethods(); ShenandoahStackWatermark::change_epoch_id(); { @@ -805,7 +806,7 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->set_has_forwarded_objects(true); // Arm nmethods/stack for concurrent processing - ShenandoahCodeRoots::arm_nmethods_for_evac(); + ShenandoahCodeRoots::arm_nmethods(); ShenandoahStackWatermark::change_epoch_id(); } else { @@ -1035,14 +1036,10 @@ void ShenandoahConcurrentGC::op_class_unloading() { class ShenandoahEvacUpdateCodeCacheClosure : public NMethodClosure { private: - BarrierSetNMethod* const _bs; ShenandoahEvacuateUpdateMetadataClosure _cl; public: - ShenandoahEvacUpdateCodeCacheClosure() : - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()), - _cl() { - } + ShenandoahEvacUpdateCodeCacheClosure() : _cl() {} void do_nmethod(nmethod* n) { ShenandoahNMethod* data = ShenandoahNMethod::gc_data(n); @@ -1050,8 +1047,8 @@ class ShenandoahEvacUpdateCodeCacheClosure : public NMethodClosure { // Setup EvacOOM scope below reentrant lock to avoid deadlock with // nmethod_entry_barrier ShenandoahEvacOOMScope oom; - data->oops_do(&_cl, true/*fix relocation*/); - _bs->disarm(n); + data->oops_do(&_cl, /* fix_relocations = */ true); + ShenandoahNMethod::disarm_nmethod(n); } }; @@ -1268,10 +1265,10 @@ bool ShenandoahConcurrentGC::entry_final_roots() { return true; } -void ShenandoahConcurrentGC::op_verify_final_roots() { - if (VerifyAfterGC) { - Universe::verify(); - } +void ShenandoahConcurrentGC::op_verify_final() { + assert(ShenandoahVerify, "Should have been checked before"); + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + heap->verifier()->verify_after_gc(_generation); } void ShenandoahConcurrentGC::op_cleanup_complete() { @@ -1356,11 +1353,11 @@ const char* ShenandoahConcurrentGC::conc_reset_after_collect_event_message() con } } -const char* ShenandoahConcurrentGC::verify_final_roots_event_message() const { +const char* ShenandoahConcurrentGC::verify_final_event_message() const { if (ShenandoahHeap::heap()->unload_classes()) { - SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final Roots", " (unload classes)"); + SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", " (unload classes)"); } else { - SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final Roots", ""); + SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", ""); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index ba228901d722..fde585b4aa9c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -43,7 +43,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { friend class VM_ShenandoahFinalMarkStartEvac; friend class VM_ShenandoahInitUpdateRefs; friend class VM_ShenandoahFinalUpdateRefs; - friend class VM_ShenandoahFinalRoots; + friend class VM_ShenandoahFinalVerify; protected: ShenandoahConcurrentMark _mark; @@ -69,7 +69,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { void vmop_entry_final_mark(); void vmop_entry_init_update_refs(); void vmop_entry_final_update_refs(); - void vmop_entry_verify_final_roots(); + void vmop_entry_final_verify(); // Entry methods to normally STW GC operations. These set up logging, monitoring // and workers for next VM operation @@ -77,7 +77,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { void entry_final_mark(); void entry_init_update_refs(); void entry_final_update_refs(); - void entry_verify_final_roots(); + void entry_final_verify(); // Entry methods to normally concurrent GC operations. These set up logging, monitoring // for concurrent operation. @@ -122,7 +122,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { void op_update_thread_roots(); void op_final_update_refs(); - void op_verify_final_roots(); + void op_verify_final(); void op_cleanup_complete(); void op_reset_after_collect(); @@ -143,7 +143,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { // passing around the logging/tracing systems const char* init_mark_event_message() const; const char* final_mark_event_message() const; - const char* verify_final_roots_event_message() const; + const char* verify_final_event_message() const; const char* conc_final_roots_event_message() const; const char* conc_mark_event_message() const; const char* conc_reset_event_message() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 367a15abfa49..fb716aef21e2 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/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 4c6e82c86a58..6175f15676cc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -346,7 +346,8 @@ void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) { void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point) { assert (point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set"); ShenandoahHeap* const heap = ShenandoahHeap::heap(); - ShenandoahGCSession session(cause, heap->global_generation()); + ShenandoahGCSession session(cause, heap->global_generation(), true, + point == ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle); heap->increment_total_collections(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 592c5bffa5a7..1807383123b3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -2678,8 +2678,11 @@ void ShenandoahFreeSet::reduce_young_reserve(size_t adjusted_young_reserve, size * 1. Memory currently available within old and young * 2. Trashed regions currently residing in young and old, which will become available momentarily * 3. The value of old_generation->get_region_balance() which represents the number of regions that we plan - * to transfer from old generation to young generation. Prior to each invocation of compute_young_and_old_reserves(), - * this value should computed by ShenandoahGenerationalHeap::compute_old_generation_balance(). + * to transfer from old generation to young generation. At the end of each GC cycle, we reset region_balance + * to zero. As we prepare to rebuild free set at the end of update-refs, we call + * ShenandoahGenerationalHeap::compute_old_generation_balance() to compute a new value of region_balance. + * This allows us to expand or shrink the size of the Old Collector reserves based on anticipated needs of + * the next GC cycle. */ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regions, size_t old_trashed_regions, size_t& young_reserve_result, size_t& old_reserve_result) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index eeff0fde87c4..f7ba1f05f476 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -680,32 +680,18 @@ using idx_t = ShenandoahSimpleBitMap::idx_t; } 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 21b1fd9e0a8a..34092a744d53 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 7d082e4a8b00..9e9ad0245114 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 } { @@ -310,16 +301,9 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); ShenandoahHeapLocker locker(heap->lock()); - - // We are preparing for evacuation. + // At start of evacation, we do NOT compute_old_generation_balance() size_t young_trashed_regions, old_trashed_regions, first_old, last_old, num_old; _free_set->prepare_to_rebuild(young_trashed_regions, old_trashed_regions, first_old, last_old, num_old); - if (heap->mode()->is_generational()) { - ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - size_t allocation_runway = - gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_trashed_regions); - gen_heap->compute_old_generation_balance(allocation_runway, old_trashed_regions, young_trashed_regions); - } _free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index aa6a4a9bab2a..bbad82de1dcb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -628,11 +628,10 @@ void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const ShenandoahGCRequest& request) { assert(_degen_point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set"); - request.generation->heuristics()->record_degenerated_cycle_start(ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle - == _degen_point); _heap->increment_total_collections(false); - ShenandoahGCSession session(request.cause, request.generation); + ShenandoahGCSession session(request.cause, request.generation, true, + _degen_point == ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle); ShenandoahDegenGC gc(_degen_point, request.generation); gc.collect(request.cause); _degen_point = ShenandoahGC::_degenerated_unset; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index a51449e91f49..1694121b9554 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -406,11 +406,14 @@ template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); +// Call this function at the end of a GC cycle in order to establish proper sizes of young and old reserves, +// setting the old-generation balance so that GC can perform the anticipated evacuations. +// // Make sure old-generation is large enough, but no larger than is necessary, to hold mixed evacuations // and promotions, if we anticipate either. Any deficit is provided by the young generation, subject to // mutator_xfer_limit, and any surplus is transferred to the young generation. mutator_xfer_limit is -// the maximum we're able to transfer from young to old. This is called at the end of GC, as we prepare -// for the idle span that precedes the next GC. +// the maximum we're able to transfer from young to old. The mutator_xfer_limit constrains the transfer +// of memory from young to old. It does not limit young reserves. void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t mutator_xfer_limit, size_t old_trashed_regions, size_t young_trashed_regions) { shenandoah_assert_heaplocked(); @@ -462,11 +465,17 @@ void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t mutator_x bound_on_old_reserve)); assert(mutator_xfer_limit <= young_available, "Cannot transfer (%zu) memory that is not available (%zu)", mutator_xfer_limit, young_available); - // Young reserves are to be taken out of the mutator_xfer_limit. - if (young_reserve > mutator_xfer_limit) { - young_reserve = mutator_xfer_limit; + + if (young_reserve > young_available) { + young_reserve = young_available; + } + // We allow young_reserve to exceed mutator_xfer_limit. Essentially, this means the GC is already behind the pace + // of mutator allocations, and we'll need to trigger the next GC as soon as possible. + if (mutator_xfer_limit > young_reserve) { + mutator_xfer_limit -= young_reserve; + } else { + mutator_xfer_limit = 0; } - mutator_xfer_limit -= young_reserve; // Decide how much old space we should reserve for a mixed collection size_t proposed_reserve_for_mixed = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 75d3ade4e491..1efe6ae963f5 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) { @@ -1650,7 +1656,8 @@ void ShenandoahHeap::set_active_generation(ShenandoahGeneration* generation) { _active_generation = generation; } -void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation) { +void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation, + bool is_degenerated, bool is_out_of_cycle) { shenandoah_policy()->record_collection_cause(cause); const GCCause::Cause current = gc_cause(); @@ -1659,7 +1666,11 @@ void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* set_gc_cause(cause); - generation->heuristics()->record_cycle_start(); + if (is_degenerated) { + generation->heuristics()->record_degenerated_cycle_start(is_out_of_cycle); + } else { + generation->heuristics()->record_cycle_start(); + } } void ShenandoahHeap::on_cycle_end(ShenandoahGeneration* generation) { @@ -2340,24 +2351,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 ab7dd00b7743..be40220e40fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -564,7 +564,7 @@ class ShenandoahHeap : public CollectedHeap { return _evac_tracker; } - void on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation); + void on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation, bool is_degenerated, bool is_out_of_cycle); void on_cycle_end(ShenandoahGeneration* generation); ShenandoahVerifier* verifier(); @@ -709,6 +709,7 @@ class ShenandoahHeap : public CollectedHeap { 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/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 3db11000af52..c031569b7c63 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -568,7 +568,6 @@ void ShenandoahHeapRegion::recycle_internal() { _top_at_evac_start = _bottom; _mixed_candidate_garbage_words = 0; - set_top(bottom()); clear_live_data(); reset_alloc_metadata(); heap->marking_context()->reset_top_at_mark_start(this); @@ -580,16 +579,21 @@ void ShenandoahHeapRegion::recycle_internal() { if (ZapUnusedHeapArea) { SpaceMangler::mangle_region(MemRegion(bottom(), end())); } + set_top(bottom()); + set_affiliation(FREE); + // Lastly, set region state to empty make_empty(); - set_affiliation(FREE); } // Upon return, this region has been recycled. We try to recycle it. // We may fail if some other thread recycled it before we do. void ShenandoahHeapRegion::try_recycle_under_lock() { shenandoah_assert_heaplocked(); - if (is_trash() && _recycling.try_set()) { + if (!is_trash()) { + return; + } + if (_recycling.try_set()) { if (is_trash()) { // At freeset rebuild time, which precedes recycling of collection set, we treat all cset regions as // part of capacity, as empty, as fully available, and as unaffiliated. This provides short-lived optimism @@ -609,6 +613,7 @@ void ShenandoahHeapRegion::try_recycle_under_lock() { os::naked_yield(); } } + assert(!is_trash(), "Must not"); } } @@ -616,7 +621,10 @@ void ShenandoahHeapRegion::try_recycle_under_lock() { // some GC worker thread has taken responsibility to recycle the region, eventually. void ShenandoahHeapRegion::try_recycle() { shenandoah_assert_not_heaplocked(); - if (is_trash() && _recycling.try_set()) { + if (!is_trash()) { + return; + } + if (_recycling.try_set()) { // Double check region state after win the race to set recycling flag if (is_trash()) { // At freeset rebuild time, which precedes recycling of collection set, we treat all cset regions as @@ -840,7 +848,7 @@ void ShenandoahHeapRegion::set_state(RegionState to) { evt.set_to(to); evt.commit(); } - _state.store_relaxed(to); + _state.release_store(to); } void ShenandoahHeapRegion::record_pin() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 569b64f756b9..e27bbbb737d8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -218,7 +218,7 @@ class ShenandoahHeapRegion { bool is_alloc_allowed() const { auto cur_state = state(); return is_empty_state(cur_state) || cur_state == _regular || cur_state == _pinned; } bool is_stw_move_allowed() const { auto cur_state = state(); return cur_state == _regular || cur_state == _cset || (ShenandoahHumongousMoves && cur_state == _humongous_start); } - RegionState state() const { return _state.load_relaxed(); } + RegionState state() const { return _state.load_acquire(); } int state_ordinal() const { return region_state_to_ordinal(state()); } void record_pin(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp index ff1e3368e876..3e809ea84b9b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp @@ -77,7 +77,8 @@ ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : } ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { - if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); + 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 560de816db90..1d2cd97b75d1 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/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp index 7c91df191e54..5041419b2c75 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp @@ -38,15 +38,19 @@ class ShenandoahLock { shenandoah_padding(0); Atomic _state; shenandoah_padding(1); +#ifdef ASSERT Atomic _owner; shenandoah_padding(2); +#endif template void contended_lock_internal(JavaThread* java_thread); static void yield_or_sleep(int &yields); public: - ShenandoahLock() : _state(unlocked), _owner(nullptr) {}; + ShenandoahLock() : _state(unlocked) { + DEBUG_ONLY(_owner.store_relaxed(nullptr);) + }; void lock(bool allow_block_for_safepoint = false) { assert(_owner.load_relaxed() != Thread::current(), "reentrant locking attempt, would deadlock"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 594ad614d90b..1b9532b3748e 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 1ddd8e1c0323..82b027faca26 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 000000000000..e2215ea58efe --- /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 000000000000..7605b69eb7ee --- /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/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index a454de68f006..6a316e2265a9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -112,8 +112,8 @@ class outputStream; f(conc_update_card_table, "Concurrent Update Cards") \ f(conc_final_roots, "Concurrent Final Roots") \ f(promote_in_place, " Promote Regions") \ - f(final_roots_gross, "Pause Verify Final Roots (G)") \ - f(final_roots, "Pause Verify Final Roots (N)") \ + f(final_verify_gross, "Pause Final Verify (G)") \ + f(final_verify, "Pause Final Verify (N)") \ \ f(init_update_refs_gross, "Pause Init Update Refs (G)") \ f(init_update_refs, "Pause Init Update Refs (N)") \ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index 7b68e6ac625a..80825ac43ad6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -200,9 +200,6 @@ ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTi void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { NMethodToOopClosure code_blob_cl(oops, NMethodToOopClosure::FixRelocations); ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(oops); - NMethodToOopClosure* adjust_code_closure = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&nmethods_and_disarm_Cl) : - static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -211,7 +208,7 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { _cld_roots.cld_do(&adjust_cld_closure, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.nmethods_do(adjust_code_closure, worker_id); + _code_roots.nmethods_do(&nmethods_and_disarm_Cl, worker_id); _thread_roots.oops_do(oops, nullptr, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index 6aebec281636..fa24b2bab3f9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -141,6 +141,49 @@ class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure { } }; +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* @@ -172,10 +215,6 @@ template void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { NMethodToOopClosure update_nmethods(keep_alive, NMethodToOopClosure::FixRelocations); ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(keep_alive); - NMethodToOopClosure* codes_cl = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&nmethods_and_disarm_Cl) : - static_cast(&update_nmethods); - CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -184,7 +223,7 @@ void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAliv _cld_roots.cld_do(&clds, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.nmethods_do(codes_cl, worker_id); + _code_roots.nmethods_do(&nmethods_and_disarm_Cl, worker_id); _thread_roots.oops_do(keep_alive, nullptr, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index 0bee8b4cf420..e106cc37627e 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 117984a6d41c..73935ed4e91c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -74,7 +74,7 @@ void ShenandoahSTWMark::mark() { // Arm all nmethods. Even though this is STW mark, some marking code // piggybacks on nmethod barriers for special instances. - ShenandoahCodeRoots::arm_nmethods_for_mark(); + ShenandoahCodeRoots::arm_nmethods(); // Weak reference processing ShenandoahReferenceProcessor* rp = _generation->ref_processor(); @@ -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 53f00e64a037..244ed7edd4c6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -413,7 +413,7 @@ class ShenandoahCardCluster: public CHeapObj { } ~ShenandoahCardCluster() { - FREE_C_HEAP_ARRAY(crossing_info, _object_starts); + FREE_C_HEAP_ARRAY(_object_starts); _object_starts = nullptr; } @@ -751,7 +751,7 @@ class ShenandoahScanRemembered: public CHeapObj { 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 82a759e34dbd..d0029b60167c 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 1f3ce76cc1ce..5295af51eff9 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 b1b923bbfceb..e9a5cf99fdd8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -67,6 +67,9 @@ class ShenandoahThreadLocalData { ShenandoahEvacuationStats* _evacuation_stats; + Atomic _invisible_root; + Atomic _invisible_root_word_size; + ShenandoahThreadLocalData(); ~ShenandoahThreadLocalData(); @@ -206,6 +209,25 @@ class ShenandoahThreadLocalData { 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/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp index dea47fcbf4f7..5af2e2748332 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp @@ -56,15 +56,14 @@ const char* ShenandoahGCSession::cycle_end_message(ShenandoahGenerationType type } } -ShenandoahGCSession::ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation) : +ShenandoahGCSession::ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation, + bool is_degenerated, bool is_out_of_cycle) : _heap(ShenandoahHeap::heap()), _generation(generation), _timer(_heap->gc_timer()), _tracer(_heap->tracer()) { assert(!ShenandoahGCPhase::is_current_phase_valid(), "No current GC phase"); - - _heap->on_cycle_start(cause, _generation); - + _heap->on_cycle_start(cause, _generation, is_degenerated, is_out_of_cycle); _timer->register_gc_start(); _tracer->report_gc_start(cause, _timer->gc_start()); _heap->trace_heap_before_gc(_tracer); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index 6ef4cd7c702b..1ed6e43e3e14 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -70,7 +70,8 @@ class ShenandoahGCSession : public StackObj { static const char* cycle_end_message(ShenandoahGenerationType type); public: - ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation); + ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation, + bool is_degenerated = false, bool is_out_of_cycle = false); ~ShenandoahGCSession(); }; @@ -187,7 +188,7 @@ class ShenandoahSafepoint : public AllStatic { type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac || type == VM_Operation::VMOp_ShenandoahInitUpdateRefs || type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs || - type == VM_Operation::VMOp_ShenandoahFinalRoots || + type == VM_Operation::VMOp_ShenandoahFinalVerify || type == VM_Operation::VMOp_ShenandoahFullGC || type == VM_Operation::VMOp_ShenandoahDegeneratedGC; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index 6b45842f7817..97dd7e5cda1a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -135,12 +135,12 @@ void VM_ShenandoahFinalUpdateRefs::doit() { _gc->entry_final_update_refs(); } -VM_ShenandoahFinalRoots::VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc) +VM_ShenandoahFinalVerify::VM_ShenandoahFinalVerify(ShenandoahConcurrentGC* gc) : VM_ShenandoahOperation(gc->generation()), _gc(gc) { } -void VM_ShenandoahFinalRoots::doit() { - ShenandoahGCPauseMark mark(_gc_id, "Final Roots", SvcGCMarker::CONCURRENT); +void VM_ShenandoahFinalVerify::doit() { + ShenandoahGCPauseMark mark(_gc_id, "Final Verify", SvcGCMarker::CONCURRENT); set_active_generation(); - _gc->entry_verify_final_roots(); + _gc->entry_final_verify(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp index d565a3df22c9..f8b99c71b14c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp @@ -38,7 +38,7 @@ class ShenandoahFullGC; // - VM_ShenandoahFinalMarkStartEvac: finish up concurrent marking, and start evacuation // - VM_ShenandoahInitUpdateRefs: initiate update references // - VM_ShenandoahFinalUpdateRefs: finish up update references -// - VM_ShenandoahFinalRoots: finish up roots on a non-evacuating cycle +// - VM_ShenandoahFinalVerify: final verification at the end of the cycle // - VM_ShenandoahReferenceOperation: // - VM_ShenandoahFullGC: do full GC // - VM_ShenandoahDegeneratedGC: do STW degenerated GC @@ -127,12 +127,12 @@ class VM_ShenandoahFinalUpdateRefs: public VM_ShenandoahOperation { void doit() override; }; -class VM_ShenandoahFinalRoots: public VM_ShenandoahOperation { +class VM_ShenandoahFinalVerify: public VM_ShenandoahOperation { ShenandoahConcurrentGC* const _gc; public: - explicit VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc); - VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalRoots; } - const char* name() const override { return "Shenandoah Final Roots"; } + explicit VM_ShenandoahFinalVerify(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalVerify; } + const char* name() const override { return "Shenandoah Final Verify"; } void doit() override; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index afef11640c96..a801023fcc40 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) { @@ -1180,7 +1180,7 @@ void ShenandoahVerifier::verify_before_update_refs(ShenandoahGeneration* generat ); } -// We have not yet cleanup (reclaimed) the collection set +// We have not yet cleaned up (reclaimed) the collection set void ShenandoahVerifier::verify_after_update_refs(ShenandoahGeneration* generation) { verify_at_safepoint( generation, @@ -1197,6 +1197,23 @@ void ShenandoahVerifier::verify_after_update_refs(ShenandoahGeneration* generati ); } +// We have not yet cleaned up (reclaimed) the collection set +void ShenandoahVerifier::verify_after_gc(ShenandoahGeneration* generation) { + verify_at_safepoint( + 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_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 + // expect generation and heap sizes to match exactly, including trash + _verify_size_exact_including_trash, + _verify_gcstate_stable // GC state was turned off + ); +} + void ShenandoahVerifier::verify_after_degenerated(ShenandoahGeneration* generation) { verify_at_safepoint( generation, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index 7e683cf7af88..0479d5f67ce1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -220,6 +220,7 @@ class ShenandoahVerifier : public CHeapObj { void verify_before_evacuation(ShenandoahGeneration* generation); void verify_before_update_refs(ShenandoahGeneration* generation); void verify_after_update_refs(ShenandoahGeneration* generation); + void verify_after_gc(ShenandoahGeneration* generation); void verify_before_fullgc(ShenandoahGeneration* generation); void verify_after_fullgc(ShenandoahGeneration* generation); void verify_after_degenerated(ShenandoahGeneration* generation); diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index bbfa19934d99..2c5ba726ef2e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -560,9 +560,6 @@ product(bool, ShenandoahLoadRefBarrier, true, DIAGNOSTIC, \ "Turn on/off load-reference barriers in Shenandoah") \ \ - product(bool, ShenandoahStackWatermarkBarrier, true, DIAGNOSTIC, \ - "Turn on/off stack watermark barriers in Shenandoah") \ - \ develop(bool, ShenandoahVerifyOptoBarriers, trueInDebug, \ "Verify no missing barriers in C2.") \ \ diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.cpp b/src/hotspot/share/gc/z/zForwardingAllocator.cpp index 451a1d627541..37b5b8f520c1 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 4578a3eec4e2..cbe28e92c513 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; - - bool use_cp_cache() const { return _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 + 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 ab66030b6cdb..03340fbe5bff 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 629cca706aeb..6f77e95f5bd0 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 e7b35b121a25..dd183f36ea28 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -36,6 +36,7 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/linkResolver.hpp" +#include "interpreter/oopMapCache.hpp" #include "interpreter/templateTable.hpp" #include "jvm_io.h" #include "logging/log.hpp" @@ -1516,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 @@ -1527,4 +1530,17 @@ bool InterpreterRuntime::is_preemptable_call(address entry_point) { entry_point == CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache) || entry_point == CAST_FROM_FN_PTR(address, InterpreterRuntime::_new); } + +void InterpreterRuntime::generate_oop_map_alot() { + JavaThread* current = JavaThread::current(); + LastFrameAccessor last_frame(current); + if (last_frame.is_interpreted_frame()) { + ResourceMark rm(current); + InterpreterOopMap mask; + methodHandle mh(current, last_frame.method()); + int bci = last_frame.bci(); + log_info(generateoopmap)("Generating oopmap for method %s at bci %d", mh->name_and_sig_as_C_string(), bci); + OopMapCache::compute_one_oop_map(mh, bci, &mask); + } +} #endif // ASSERT diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp index 70ceeb0b2af4..3228027fa939 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.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 @@ -173,6 +173,8 @@ class InterpreterRuntime: AllStatic { // Virtual Thread Preemption DEBUG_ONLY(static bool is_preemptable_call(address entry_point);) + + DEBUG_ONLY(static void generate_oop_map_alot();) }; diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 5a1ad7b78833..34e226b00bfb 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -92,11 +92,8 @@ class OopMapForCacheEntry: public GenerateOopMap { }; -OopMapForCacheEntry::OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry* entry) : GenerateOopMap(method) { - _bci = bci; - _entry = entry; - _stack_top = -1; -} +OopMapForCacheEntry::OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry* entry) : + GenerateOopMap(method, /*all_exception_edges*/ true), _entry(entry), _bci(bci), _stack_top(-1) { } bool OopMapForCacheEntry::compute_map(Thread* current) { @@ -107,6 +104,11 @@ bool OopMapForCacheEntry::compute_map(Thread* current) { } else { ResourceMark rm; if (!GenerateOopMap::compute_map(current)) { + // If compute_map fails, print the exception message, which is generated if + // this is a JavaThread, otherwise compute_map calls fatal so we don't get here. + if (exception() != nullptr) { + exception()->print(); + } fatal("Unrecoverable verification or out-of-memory error"); return false; } @@ -154,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]); } } @@ -286,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;) } } @@ -315,6 +317,9 @@ void OopMapCacheEntry::fill(const methodHandle& method, int bci) { } else { OopMapForCacheEntry gen(method, bci, this); if (!gen.compute_map(Thread::current())) { + if (gen.exception() != nullptr) { + gen.exception()->print(); + } fatal("Unrecoverable verification or out-of-memory error"); } } diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index a6e97ab227a2..32710595d279 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/sampling/samplePriorityQueue.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp index 644cd25ec8a2..5eac068467ff 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 11e211f6505b..1650ad7d9c0f 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 b212ee4ccba4..ec8ab36d75a2 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 1eb057b564ec..39a1c621888d 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 0721604b1c1e..cb9811e7cae3 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 2a977f9e8231..767036b57f2d 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 d9081efa08cc..ea031f9f2056 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 6d6908234a3b..22028a96e556 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 0be2d92ed197..ce4c920cf8b4 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 c443434800ae..3e828d51ec36 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 176660d83027..bd9e97d9877a 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 a93b1ca58f66..933482929c76 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 b883dbccacff..1ba45cc050fa 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 9d6d19d739eb..c805a3e10773 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 8f308b1f0150..4714cd65f8a0 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 e3c68b49b130..f74e614e5397 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 667c76ec306d..28b0d697b147 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.hpp b/src/hotspot/share/memory/allocation.hpp index 15b7750a363e..d43add7cb669 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); @@ -374,9 +374,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 +479,8 @@ class AnyObj { #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 +497,18 @@ class AnyObj { #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_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(old, old_size, new_size)\ + (REALLOC_RETURN_TYPE(old)) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(*old), (new_size) * sizeof(*old)) -#define FREE_RESOURCE_ARRAY(type, old, size)\ - resource_free_bytes(Thread::current(), (char*)(old), (size) * sizeof(type)) +#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_IN_THREAD(thread, type, old, size)\ - resource_free_bytes(thread, (char*)(old), (size) * sizeof(type)) +#define FREE_RESOURCE_ARRAY(obj, size)\ + resource_free_bytes(Thread::current(), (char*)(obj), (size) * sizeof(*obj)) -#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 +531,14 @@ class AnyObj { #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 +547,9 @@ class AnyObj { #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 7d88c79ca529..252e511f615b 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -240,12 +240,12 @@ class Arena : public CHeapObjBase { #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 aae3c99a6346..5abb7e4ddcce 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 3c4819260255..dde4b0ace9a2 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/rootChunkArea.cpp b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp index a178e1227881..39407b469999 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 ac42dd13c6c9..20e5528e9bc9 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 @@ class MetaspaceClosure { // 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 @@ class MetaspaceClosure { 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 @@ class MetaspaceClosure { 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 @@ class MetaspaceClosure { 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 @@ class MetaspaceClosure { 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 @@ class MetaspaceClosure { // // 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 @@ class MetaspaceClosure { 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 adf6805521b2..2dbba34ab676 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 bab652c17ea9..63f7ed61d17b 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 a78b245cc077..aecaa1cac22d 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 9a2ecd57ecc2..bbf93c5d8983 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 6c5ab691f6de..1fc05133d222 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 ae732a4b0d3a..7054249319f3 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -264,7 +264,7 @@ class VMATree : public CHeapObjBase { } ~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 b972c54a0648..bbf5cd8722e9 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 82067e007ea3..0c720c854782 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 @@ class Array: public MetaspaceObj { 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 30cf2e38f773..e6c8ef94a126 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/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index 09912aeaf635..56f3e7e03259 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1168,42 +1168,46 @@ void GenerateOopMap::interp_bb(BasicBlock *bb) { } void GenerateOopMap::do_exception_edge(BytecodeStream* itr) { - // Only check exception edge, if bytecode can trap - if (!Bytecodes::can_trap(itr->code())) return; - switch (itr->code()) { - case Bytecodes::_aload_0: - // These bytecodes can trap for rewriting. We need to assume that - // they do not throw exceptions to make the monitor analysis work. - return; - case Bytecodes::_ireturn: - case Bytecodes::_lreturn: - case Bytecodes::_freturn: - case Bytecodes::_dreturn: - case Bytecodes::_areturn: - case Bytecodes::_return: - // If the monitor stack height is not zero when we leave the method, - // then we are either exiting with a non-empty stack or we have - // found monitor trouble earlier in our analysis. In either case, - // assume an exception could be taken here. - if (_monitor_top == 0) { + // Only check exception edge, if bytecode can trap or if async exceptions can be thrown + // from any bytecode in the interpreter when single stepping. + if (!_all_exception_edges) { + if (!Bytecodes::can_trap(itr->code())) return; + switch (itr->code()) { + case Bytecodes::_aload_0: + // These bytecodes can trap for rewriting. We need to assume that + // they do not throw exceptions to make the monitor analysis work. return; - } - break; - case Bytecodes::_monitorexit: - // If the monitor stack height is bad_monitors, then we have detected a - // monitor matching problem earlier in the analysis. If the - // monitor stack height is 0, we are about to pop a monitor - // off of an empty stack. In either case, the bytecode - // could throw an exception. - if (_monitor_top != bad_monitors && _monitor_top != 0) { - return; - } - break; + case Bytecodes::_ireturn: + case Bytecodes::_lreturn: + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: + case Bytecodes::_return: + // If the monitor stack height is not zero when we leave the method, + // then we are either exiting with a non-empty stack or we have + // found monitor trouble earlier in our analysis. In either case, + // assume an exception could be taken here. + if (_monitor_top == 0) { + return; + } + break; - default: - break; + case Bytecodes::_monitorexit: + // If the monitor stack height is bad_monitors, then we have detected a + // monitor matching problem earlier in the analysis. If the + // monitor stack height is 0, we are about to pop a monitor + // off of an empty stack. In either case, the bytecode + // could throw an exception. + if (_monitor_top != bad_monitors && _monitor_top != 0) { + return; + } + break; + + default: + break; + } } if (_has_exceptions) { @@ -2055,12 +2059,12 @@ void GenerateOopMap::print_time() { // // ============ Main Entry Point =========== // -GenerateOopMap::GenerateOopMap(const methodHandle& method) { +GenerateOopMap::GenerateOopMap(const methodHandle& method, bool all_exception_edges) : // We have to initialize all variables here, that can be queried directly - _method = method; - _max_locals=0; - _init_vars = nullptr; -} + _method(method), + _max_locals(0), + _all_exception_edges(all_exception_edges), + _init_vars(nullptr) {} bool GenerateOopMap::compute_map(Thread* current) { #ifndef PRODUCT @@ -2187,7 +2191,7 @@ void GenerateOopMap::result_for_basicblock(int bci) { // Find basicblock and report results BasicBlock* bb = get_basic_block_containing(bci); guarantee(bb != nullptr, "no basic block for bci"); - assert(bb->is_reachable(), "getting result from unreachable basicblock %d", bci); + assert(bb->is_reachable(), "getting result from unreachable basicblock at bci %d", bci); bb->set_changed(true); interp_bb(bb); } diff --git a/src/hotspot/share/oops/generateOopMap.hpp b/src/hotspot/share/oops/generateOopMap.hpp index 783e295f08ad..f0fdfeda57f6 100644 --- a/src/hotspot/share/oops/generateOopMap.hpp +++ b/src/hotspot/share/oops/generateOopMap.hpp @@ -307,6 +307,7 @@ class GenerateOopMap { bool _did_relocation; // was relocation necessary bool _monitor_safe; // The monitors in this method have been determined // to be safe. + bool _all_exception_edges; // All bytecodes can reach containing exception handler. // Working Cell type state int _state_len; // Size of states @@ -455,7 +456,7 @@ class GenerateOopMap { friend class RelocCallback; public: - GenerateOopMap(const methodHandle& method); + GenerateOopMap(const methodHandle& method, bool all_exception_edges); // Compute the map - returns true on success and false on error. bool compute_map(Thread* current); @@ -516,7 +517,7 @@ class ResolveOopMapConflicts: public GenerateOopMap { #endif public: - ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { } + ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method, true) { } methodHandle do_potential_rewrite(TRAPS); }; @@ -535,7 +536,7 @@ class GeneratePairingInfo: public GenerateOopMap { CellTypeState* stack, int stack_top) {} public: - GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method) {}; + GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method, false) {}; // Call compute_map() to generate info. }; diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index d675e61cc050..9f33e6351a9a 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(); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index dd563ad34920..6c8808110249 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 @@ class InstanceKlass: public Klass { 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 diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 949441585d87..1cc17ef16588 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; } diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index e7479671dcf2..6f31619c1909 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 ) diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index ad1049ffa34b..dc0b8fa9f816 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -667,8 +667,8 @@ void MultiBranchData::print_data_on(outputStream* st, const char* extra) const { void ArgInfoData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "ArgInfoData", extra); - int nargs = number_of_args(); - for (int i = 0; i < nargs; i++) { + int args_size = size_of_args(); + for (int i = 0; i < args_size; i++) { st->print(" 0x%x", arg_modified(i)); } st->cr(); diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 196537359b53..45529618afb7 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -1751,7 +1751,7 @@ class ArgInfoData : public ArrayData { virtual bool is_ArgInfoData() const { return true; } - int number_of_args() const { + int size_of_args() const { return array_len(); } diff --git a/src/hotspot/share/oops/methodData.inline.hpp b/src/hotspot/share/oops/methodData.inline.hpp index dee14d492536..b417ba867fc8 100644 --- a/src/hotspot/share/oops/methodData.inline.hpp +++ b/src/hotspot/share/oops/methodData.inline.hpp @@ -59,7 +59,7 @@ inline uint MethodData::arg_modified(int a) { MutexLocker ml(extra_data_lock(), Mutex::_no_safepoint_check_flag); ArgInfoData* aid = arg_info(); assert(aid != nullptr, "arg_info must be not null"); - assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); + assert(a >= 0 && a < aid->size_of_args(), "valid argument number"); return aid->arg_modified(a); } @@ -68,7 +68,7 @@ inline void MethodData::set_arg_modified(int a, uint v) { MutexLocker ml(extra_data_lock(), Mutex::_no_safepoint_check_flag); ArgInfoData* aid = arg_info(); assert(aid != nullptr, "arg_info must be not null"); - assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); + assert(a >= 0 && a < aid->size_of_args(), "valid argument number"); aid->set_arg_modified(a, v); } diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index a6decdce7f0d..50f97153d8cc 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 a93e2e43a29a..1da63ce81808 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 ef017ee15ec2..606d45d4a129 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 e05df8ea716b..8da4342419b3 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(); diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index e3d3108a22e7..ce1ea8a59e29 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/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 35a9108892cc..13feeb779476 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 26b822593279..4eef2fed4156 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/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 11b23d7c3651..ccd53129a87c 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1307,7 +1307,14 @@ Node* PhaseIdealLoop::place_outside_loop(Node* useblock, IdealLoopTree* loop) co bool PhaseIdealLoop::identical_backtoback_ifs(Node *n) { - if (!n->is_If() || n->is_BaseCountedLoopEnd()) { + if (!n->is_If()) { + return false; + } + if (n->outcnt() != n->as_If()->required_outcnt()) { + assert(false, "malformed IfNode with %d outputs", n->outcnt()); + return false; + } + if (n->is_BaseCountedLoopEnd()) { return false; } if (!n->in(0)->is_Region()) { @@ -1433,7 +1440,10 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { // Check some safety conditions if (iff->is_If()) { // Classic split-if? - if (iff->in(0) != n_ctrl) { + if (iff->outcnt() != iff->as_If()->required_outcnt()) { + assert(false, "malformed IfNode with %d outputs", iff->outcnt()); + return; + } else if (iff->in(0) != n_ctrl) { return; // Compare must be in same blk as if } } else if (iff->is_CMove()) { // Trying to split-up a CMOVE diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index c7fe45084730..1521f89af4e2 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; } @@ -1671,20 +1674,24 @@ bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) { intptr_t ignore = 0; Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore); + if (base == nullptr) { + return false; + } + if (base->is_CastPP()) { base = base->in(1); } - if (req() > 3 || base == nullptr || !base->is_Phi()) { + if (req() > 3 || !base->is_Phi()) { return false; } 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; } } @@ -1779,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); } @@ -1960,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; @@ -4825,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 8efb5521e7c4..f3f656089727 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -103,15 +103,15 @@ class MemNode : public Node { // 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 @@ class MemNode : public Node { // 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 @@ class MemNode : public Node { // 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 @@ class AccessAnalyzer : StackObj { 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 3eafd97d7c18..997ce92fe1cf 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 2b599ace03ae..3d316112b2d6 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 421031fdf615..99b10c1c557e 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/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index c1303f0d0db6..e5f8043ae19a 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -704,6 +704,9 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio new_true = ifpx; } } + assert(new_false != nullptr, "iff is malformed"); + assert(new_true != nullptr, "iff is malformed"); + _igvn.remove_dead_node(new_iff, PhaseIterGVN::NodeOrigin::Speculative); // Lazy replace IDOM info with the region's dominator replace_node_and_forward_ctrl(iff, region_dom); diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 548df58eb35c..014f41f82cc1 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 54cb1d20cd00..387c1c46ba9c 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -198,6 +198,7 @@ class CmpPNode : public CmpNode { 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 4f67aff9b070..47def1aed1e7 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 214173c02f7d..32ade413673c 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 85207fddf29e..d6a435d34d1a 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -867,8 +867,7 @@ static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, // Create object to hold arguments for the JavaCall, and associate it with // the jni parser ResourceMark rm(THREAD); - int number_of_parameters = method->size_of_parameters(); - JavaCallArguments java_args(number_of_parameters); + JavaCallArguments java_args(method->size_of_parameters()); assert(method->is_static(), "method should be static"); @@ -2896,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 66cb68b44b07..5fe5378995b8 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 5077a1743b9f..3037ffa50638 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 fca348fda261..98d8cfd990d2 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/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 04cb70863cd4..9724a61ba3d7 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 08ab52ed686f..1401157911fd 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/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index c950690e8ab8..368c40abbc9b 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -702,11 +702,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; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index f50e6ddb3db5..de140fb95ff1 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1280,8 +1280,8 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) if (mdo != nullptr) { mdo->init(); ResourceMark rm(THREAD); - int arg_count = mdo->method()->size_of_parameters(); - for (int i = 0; i < arg_count; i++) { + int arg_size = mdo->method()->size_of_parameters(); + for (int i = 0; i < arg_size; i++) { mdo->set_arg_modified(i, 0); } mdo->clean_method_data(/*always_clean*/true); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 2d40ee1822ab..b8b32d89c653 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 f2bcc21e1236..2c31383f7a45 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/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index cfdcf52a5ebb..9db9c676268b 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/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 405b47e1813f..1c9653605991 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 2db9f198ddd8..8efa8f2de621 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/globals.hpp b/src/hotspot/share/runtime/globals.hpp index ac1ddec7cbc5..9d38a44cbd57 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -871,6 +871,9 @@ const int ObjectAlignmentInBytes = 8; develop(bool, TimeOopMap, false, \ "Time calls to GenerateOopMap::compute_map() in sum") \ \ + develop(bool, GenerateOopMapALot, false, \ + "Generate interpreter oopmaps at all safepoints") \ + \ develop(bool, TraceFinalizerRegistration, false, \ "Trace registration of final references") \ \ diff --git a/src/hotspot/share/runtime/hotCodeCollector.cpp b/src/hotspot/share/runtime/hotCodeCollector.cpp index 643cf3a8bbb2..6bdeee011ced 100644 --- a/src/hotspot/share/runtime/hotCodeCollector.cpp +++ b/src/hotspot/share/runtime/hotCodeCollector.cpp @@ -29,6 +29,7 @@ #include "compiler/compilerDefinitions.inline.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" +#include "oops/method.inline.hpp" #include "runtime/hotCodeCollector.hpp" #include "runtime/hotCodeSampler.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/runtime/interfaceSupport.cpp b/src/hotspot/share/runtime/interfaceSupport.cpp index 11a7d9fd41f0..6ccf63b4c5e5 100644 --- a/src/hotspot/share/runtime/interfaceSupport.cpp +++ b/src/hotspot/share/runtime/interfaceSupport.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 @@ -23,6 +23,7 @@ */ #include "gc/shared/collectedHeap.inline.hpp" +#include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -65,6 +66,10 @@ VMEntryWrapper::~VMEntryWrapper() { if (VerifyStack) { InterfaceSupport::verify_stack(); } + // Verify interpreter oopmap generation + if (GenerateOopMapALot) { + InterpreterRuntime::generate_oop_map_alot(); + } } VMNativeEntryWrapper::VMNativeEntryWrapper() { diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 77a567d4a09c..5a29a668a549 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 755a6abe0d81..bc6c0a3a4fda 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/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index c455b5f36a24..8e0c1d10e5c6 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -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 @@ -293,7 +293,8 @@ Mutex::Mutex(Rank rank, const char * name, bool allow_vm_block) : _owner(nullptr _rank = rank; _skip_rank_check = false; - assert(_rank >= static_cast(0) && _rank <= safepoint, "Bad lock rank %s: %s", rank_name(), name); + assert(_rank >= static_cast(0) && _rank <= safepoint, "Bad lock rank %d outside [0, %d]: %s", + static_cast(rank), static_cast(safepoint), name); // The allow_vm_block also includes allowing other non-Java threads to block or // allowing Java threads to block in native. @@ -324,25 +325,33 @@ static const char* _rank_names[] = { "event", "service", "stackwatermark", "tty" static const int _num_ranks = 7; -static const char* rank_name_internal(Mutex::Rank r) { +static void print_rank_name_internal(outputStream* st, Mutex::Rank r) { // Find closest rank and print out the name - stringStream st; for (int i = 0; i < _num_ranks; i++) { if (r == _ranks[i]) { - return _rank_names[i]; + st->print("%s", _rank_names[i]); } else if (r > _ranks[i] && (i < _num_ranks-1 && r < _ranks[i+1])) { int delta = static_cast(_ranks[i+1]) - static_cast(r); - st.print("%s-%d", _rank_names[i+1], delta); - return st.as_string(); + st->print("%s-%d", _rank_names[i+1], delta); } } - return "fail"; +} + +// Requires caller to have ResourceMark. +static const char* rank_name_internal(Mutex::Rank r) { + stringStream st; + print_rank_name_internal(&st, r); + return st.as_string(); } const char* Mutex::rank_name() const { return rank_name_internal(_rank); } +// Does not require caller to have ResourceMark. +void Mutex::print_rank_name(outputStream* st) const { + print_rank_name_internal(st, _rank); +} void Mutex::assert_no_overlap(Rank orig, Rank adjusted, int adjust) { int i = 0; @@ -364,7 +373,8 @@ void Mutex::print_on(outputStream* st) const { if (_allow_vm_block) { st->print("%s", " allow_vm_block"); } - DEBUG_ONLY(st->print(" %s", rank_name())); + st->print(" "); + DEBUG_ONLY(print_rank_name(st)); st->cr(); } diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index cf2b222d2daa..4d30a320cbf8 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.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 @@ -130,9 +130,11 @@ class Mutex : public CHeapObj { return _skip_rank_check; } + const char* rank_name() const; + void print_rank_name(outputStream* st) const; + public: Rank rank() const { return _rank; } - const char* rank_name() const; Mutex* next() const { return _next; } #endif // ASSERT diff --git a/src/hotspot/share/runtime/nonJavaThread.cpp b/src/hotspot/share/runtime/nonJavaThread.cpp index cb0c3f8910d2..e8f010860588 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 bc173992d7a7..9f087ad5dee0 100644 --- a/src/hotspot/share/runtime/objectMonitorTable.cpp +++ b/src/hotspot/share/runtime/objectMonitorTable.cpp @@ -192,7 +192,7 @@ class ObjectMonitorTable::Table : public CHeapObj { } ~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 d55cf454256c..f9e3a513a788 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 8e39b75deb62..a9a82a41b7e9 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 7532ada8f5ab..1502995203d7 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 d910f8662fed..9c87f87f688c 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 9594149333e6..134d1c47230f 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 352c90f913ba..3b5a6fa7ff8e 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 4c68648fec8a..d70b7dcbd34e 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 b83389a19290..27c4c5884295 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/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 5140d0401fb9..6078600c16e7 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -90,7 +90,7 @@ template(ShenandoahFinalMarkStartEvac) \ template(ShenandoahInitUpdateRefs) \ template(ShenandoahFinalUpdateRefs) \ - template(ShenandoahFinalRoots) \ + template(ShenandoahFinalVerify) \ template(ShenandoahDegeneratedGC) \ template(Exit) \ template(LinuxDllLoad) \ diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index ad9463443b2f..6ae9de055186 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 247ab50bde73..0ba7bda27197 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 9acf17b8cfd3..d57d0fb5b50c 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 bfb4546a8a19..c850a3a711fc 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 664fb5a8ef35..36db3df056f8 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 ef9babbb20dd..2d725db85b50 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/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 62d2dd29dab2..d5f6dee336b5 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 0b7713e9ca9c..e81f91282929 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 8abd846364c6..0bfa821e2561 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/istream.cpp b/src/hotspot/share/utilities/istream.cpp index ce622c2c2822..c78fa5d1efa0 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 536f65638669..9d4ece105ed9 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 ded233d48bf1..f052431d55ef 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 9c04ccbe9ab0..fb505ebe9ca2 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -385,6 +385,15 @@ class RBTree : public AbstractRBTree, COMPARATOR> { 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 381cb916405f..1bd8ba8faf8a 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 a5b53698b112..8e6528f6a3c3 100644 --- a/src/hotspot/share/utilities/resizableHashTable.hpp +++ b/src/hotspot/share/utilities/resizableHashTable.hpp @@ -45,7 +45,7 @@ class ResizeableHashTableStorage : public AnyObj { ~ResizeableHashTableStorage() { if (ALLOC_TYPE == C_HEAP) { - FREE_C_HEAP_ARRAY(Node*, _table); + FREE_C_HEAP_ARRAY(_table); } } @@ -151,7 +151,7 @@ class ResizeableHashTable : public HashTableBase< } 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 49ccf4166290..78e575a0eaf9 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 0872ce43d4b7..d133d21e52f4 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 6dacab1dc250..3ebc1b4b4ac8 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/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java index e10b0b1a7cfb..d614412b13b4 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 @@ byte[] getIV() { 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 @@ void init(int opmode, Key key, AlgorithmParameterSpec params, 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 @@ void init(int opmode, Key key, AlgorithmParameterSpec params, 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 7d2ba7f98316..517d77772877 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/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 78098e39a176..70b15bb0cd7f 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 @@ static MemorySegment ofArray(double[] doubleArray) { *

* 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/net/URL.java b/src/java.base/share/classes/java/net/URL.java index 1e86f41fd3f0..2f2c80423ce0 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 @@ *

* 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 @@ * 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 URL(String spec) throws MalformedURLException { * * 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 URL(String spec) throws MalformedURLException { * 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 String getProtocol() { /** * 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 String toExternalForm() { /** * 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 URLConnection openConnection(Proxy proxy) * 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 InputStream openStream() throws java.io.IOException { /** * 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 Object getContent() throws java.io.IOException { /** * 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/java/util/stream/Stream.java b/src/java.base/share/classes/java/util/stream/Stream.java index 1dd13133fe14..645f4f033b7c 100644 --- a/src/java.base/share/classes/java/util/stream/Stream.java +++ b/src/java.base/share/classes/java/util/stream/Stream.java @@ -1002,8 +1002,8 @@ default Stream dropWhile(Predicate predicate) { /** * Performs a reduction on the - * elements of this stream, using the provided identity, accumulation and - * combining functions. This is equivalent to: + * elements of this stream using the provided identity value, accumulation + * function, and combining function. This is equivalent to: *
{@code
      *     U result = identity;
      *     for (T element : this stream)
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 728ee2355475..a94800711cf2 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 @@ private static long allocateNativeInternal(long byteSize, long byteAlignment, Me
         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 @@ private static long allocateNativeInternal(long byteSize, long byteAlignment, Me
         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 0fd90ef6f73a..c9994ec29306 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 @@ VMStorage nextStorage(int type, boolean is32Bit) {
         // 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/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java
index 4be83d629bb1..154d14284146 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 @@ private static byte[] readOneBlock(InputStream is) throws IOException {
         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 @@ private static byte[] readOneBlock(InputStream is) throws IOException {
      * @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 @@ private static int readBERInternal(InputStream is,
                         "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 31c0f4ecb9c5..ed0fd0f55768 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 @@
 
 /**
  * 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 297727310d4f..7751f6a32bf4 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 @@ private void buildToNewKey(X509Certificate currCert, // 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/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java index fb06b02a5d45..e9588a09b3d8 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.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 @@ -281,6 +281,8 @@ public void consume(ConnectionContext context, // consumer so the state machine doesn't expect it. tc.handshakeContext.handshakeConsumers.remove( SSLHandshake.CERTIFICATE.id); + tc.handshakeContext.handshakeConsumers.remove( + SSLHandshake.COMPRESSED_CERTIFICATE.id); tc.handshakeContext.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_VERIFY.id); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java index c6897d71aa64..af5007d7899b 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java @@ -781,14 +781,6 @@ static final class T13CertificateMessage extends HandshakeMessage { } } - T13CertificateMessage(HandshakeContext handshakeContext, - byte[] requestContext, List certificates) { - super(handshakeContext); - - this.requestContext = requestContext.clone(); - this.certEntries = certificates; - } - T13CertificateMessage(HandshakeContext handshakeContext, ByteBuffer m) throws IOException { super(handshakeContext); @@ -925,16 +917,26 @@ public byte[] produce(ConnectionContext context, HandshakeMessage message) throws IOException { // The producing happens in handshake context only. HandshakeContext hc = (HandshakeContext)context; - if (hc.sslConfig.isClientMode) { - return onProduceCertificate( - (ClientHandshakeContext)context, message); - } else { - return onProduceCertificate( + T13CertificateMessage cm = hc.sslConfig.isClientMode ? + onProduceCertificate( + (ClientHandshakeContext)context, message) : + onProduceCertificate( (ServerHandshakeContext)context, message); + + // Output the handshake message. + if (hc.certDeflater == null) { + cm.write(hc.handshakeOutput); + hc.handshakeOutput.flush(); + } else { + // Replace with CompressedCertificate message + CompressedCertificate.handshakeProducer.produce(hc, cm); } + + // The handshake message has been delivered. + return null; } - private byte[] onProduceCertificate(ServerHandshakeContext shc, + private T13CertificateMessage onProduceCertificate(ServerHandshakeContext shc, HandshakeMessage message) throws IOException { ClientHelloMessage clientHello = (ClientHelloMessage)message; @@ -993,12 +995,7 @@ private byte[] onProduceCertificate(ServerHandshakeContext shc, SSLLogger.fine("Produced server Certificate message", cm); } - // Output the handshake message. - cm.write(shc.handshakeOutput); - shc.handshakeOutput.flush(); - - // The handshake message has been delivered. - return null; + return cm; } private static SSLPossession choosePossession( @@ -1045,7 +1042,7 @@ private static SSLPossession choosePossession( return pos; } - private byte[] onProduceCertificate(ClientHandshakeContext chc, + private T13CertificateMessage onProduceCertificate(ClientHandshakeContext chc, HandshakeMessage message) throws IOException { ClientHelloMessage clientHello = (ClientHelloMessage)message; SSLPossession pos = choosePossession(chc, clientHello); @@ -1091,12 +1088,7 @@ private byte[] onProduceCertificate(ClientHandshakeContext chc, SSLLogger.fine("Produced client Certificate message", cm); } - // Output the handshake message. - cm.write(chc.handshakeOutput); - chc.handshakeOutput.flush(); - - // The handshake message has been delivered. - return null; + return cm; } } @@ -1116,6 +1108,7 @@ public void consume(ConnectionContext context, HandshakeContext hc = (HandshakeContext)context; // clean up this consumer + hc.handshakeConsumers.remove(SSLHandshake.COMPRESSED_CERTIFICATE.id); hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id); // Ensure that the Certificate message has not been sent w/o diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 039399560cd6..2eceb4d9ebde 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, 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 @@ -956,6 +956,11 @@ public byte[] produce(ConnectionContext context, // update // shc.certRequestContext = crm.requestContext.clone(); + if (shc.certInflaters != null && !shc.certInflaters.isEmpty()) { + shc.handshakeConsumers.put( + SSLHandshake.COMPRESSED_CERTIFICATE.id, + SSLHandshake.COMPRESSED_CERTIFICATE); + } shc.handshakeConsumers.put(SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); shc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_VERIFY.id, diff --git a/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java b/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java new file mode 100644 index 000000000000..eff97857ef07 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * 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 sun.security.ssl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; +import javax.net.ssl.SSLProtocolException; +import sun.security.ssl.SSLExtension.ExtensionConsumer; +import sun.security.ssl.SSLExtension.SSLExtensionSpec; +import sun.security.ssl.SSLHandshake.HandshakeMessage; + +/** + * Pack of the "compress_certificate" extensions [RFC 5246]. + */ +final class CompressCertExtension { + + static final HandshakeProducer chNetworkProducer = + new CHCompressCertificateProducer(); + static final ExtensionConsumer chOnLoadConsumer = + new CHCompressCertificateConsumer(); + + static final HandshakeProducer crNetworkProducer = + new CRCompressCertificateProducer(); + static final ExtensionConsumer crOnLoadConsumer = + new CRCompressCertificateConsumer(); + + static final SSLStringizer ccStringizer = + new CompressCertificateStringizer(); + + /** + * The "signature_algorithms" extension. + */ + static final class CertCompressionSpec implements SSLExtensionSpec { + + private final int[] compressionAlgorithms; // non-null + + CertCompressionSpec( + Map> certInflaters) { + compressionAlgorithms = new int[certInflaters.size()]; + int i = 0; + for (Integer id : certInflaters.keySet()) { + compressionAlgorithms[i++] = id; + } + } + + CertCompressionSpec(HandshakeContext hc, + ByteBuffer buffer) throws IOException { + if (buffer.remaining() < 2) { // 2: the length of the list + throw hc.conContext.fatal(Alert.DECODE_ERROR, + new SSLProtocolException( + "Invalid compress_certificate: insufficient data")); + } + + byte[] algs = Record.getBytes8(buffer); + if (buffer.hasRemaining()) { + throw hc.conContext.fatal(Alert.DECODE_ERROR, + new SSLProtocolException( + "Invalid compress_certificate: unknown extra data")); + } + + if (algs.length == 0 || (algs.length & 0x01) != 0) { + throw hc.conContext.fatal(Alert.DECODE_ERROR, + new SSLProtocolException( + "Invalid compress_certificate: incomplete data")); + } + + int[] compressionAlgs = new int[algs.length / 2]; + for (int i = 0, j = 0; i < algs.length; ) { + byte hash = algs[i++]; + byte sign = algs[i++]; + compressionAlgs[j++] = ((hash & 0xFF) << 8) | (sign & 0xFF); + } + + this.compressionAlgorithms = compressionAlgs; + } + + @Override + public String toString() { + MessageFormat messageFormat = new MessageFormat( + "\"compression algorithms\": '['{0}']'", Locale.ENGLISH); + + if (compressionAlgorithms.length == 0) { + Object[] messageFields = { + "" + }; + return messageFormat.format(messageFields); + } else { + StringBuilder builder = new StringBuilder(512); + boolean isFirst = true; + for (int ca : compressionAlgorithms) { + if (isFirst) { + isFirst = false; + } else { + builder.append(", "); + } + + builder.append(CompressionAlgorithm.nameOf(ca)); + } + + Object[] messageFields = { + builder.toString() + }; + + return messageFormat.format(messageFields); + } + } + } + + private static final + class CompressCertificateStringizer implements SSLStringizer { + + @Override + public String toString(HandshakeContext hc, ByteBuffer buffer) { + try { + return (new CertCompressionSpec(hc, buffer)).toString(); + } catch (IOException ioe) { + // For debug logging only, so please swallow exceptions. + return ioe.getMessage(); + } + } + } + + /** + * Network data producer of a "compress_certificate" extension in + * the ClientHello handshake message. + */ + private static final + class CHCompressCertificateProducer implements HandshakeProducer { + + // Prevent instantiation of this class. + private CHCompressCertificateProducer() { + // blank + } + + @Override + public byte[] produce(ConnectionContext context, + HandshakeMessage message) throws IOException { + // The producing happens in client side only. + return produceCompCertExt(context, + SSLExtension.CH_COMPRESS_CERTIFICATE); + } + } + + /** + * Network data consumer of a "compress_certificate" extension in + * the ClientHello handshake message. + */ + private static final + class CHCompressCertificateConsumer implements ExtensionConsumer { + + // Prevent instantiation of this class. + private CHCompressCertificateConsumer() { + // blank + } + + @Override + public void consume(ConnectionContext context, + HandshakeMessage message, ByteBuffer buffer) + throws IOException { + // The consuming happens in server side only. + consumeCompCertExt(context, buffer, + SSLExtension.CH_COMPRESS_CERTIFICATE); + } + } + + /** + * Network data producer of a "compress_certificate" extension in + * the CertificateRequest handshake message. + */ + private static final + class CRCompressCertificateProducer implements HandshakeProducer { + + // Prevent instantiation of this class. + private CRCompressCertificateProducer() { + // blank + } + + @Override + public byte[] produce(ConnectionContext context, + HandshakeMessage message) throws IOException { + // The producing happens in server side only. + return produceCompCertExt(context, + SSLExtension.CR_COMPRESS_CERTIFICATE); + } + } + + /** + * Network data consumer of a "compress_certificate" extension in + * the CertificateRequest handshake message. + */ + private static final + class CRCompressCertificateConsumer implements ExtensionConsumer { + + // Prevent instantiation of this class. + private CRCompressCertificateConsumer() { + // blank + } + + @Override + public void consume(ConnectionContext context, + HandshakeMessage message, ByteBuffer buffer) + throws IOException { + // The consuming happens in client side only. + consumeCompCertExt(context, buffer, + SSLExtension.CR_COMPRESS_CERTIFICATE); + } + } + + private static byte[] produceCompCertExt( + ConnectionContext context, SSLExtension extension) + throws IOException { + + HandshakeContext hc = (HandshakeContext) context; + // Is it a supported and enabled extension? + if (!hc.sslConfig.isAvailable(extension)) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Ignore unavailable " + + "compress_certificate extension"); + } + return null; + } + + // Produce the extension. + hc.certInflaters = CompressionAlgorithm.getInflaters(); + + if (hc.certInflaters.isEmpty()) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("Unable to produce the extension: " + + "no certificate compression inflaters defined"); + } + return null; + } + + int vectorLen = CompressionAlgorithm.sizeInRecord() * + hc.certInflaters.size(); + byte[] extData = new byte[vectorLen + 1]; + ByteBuffer m = ByteBuffer.wrap(extData); + Record.putInt8(m, vectorLen); + for (Integer algId : hc.certInflaters.keySet()) { + Record.putInt16(m, algId); + } + + // Update the context. + hc.handshakeExtensions.put( + extension, new CertCompressionSpec(hc.certInflaters)); + + return extData; + } + + private static void consumeCompCertExt(ConnectionContext context, + ByteBuffer buffer, SSLExtension extension) throws IOException { + + HandshakeContext hc = (HandshakeContext) context; + // Is it a supported and enabled extension? + if (!hc.sslConfig.isAvailable(extension)) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Ignore unavailable " + + "compress_certificate extension"); + } + return; // ignore the extension + } + + // Parse the extension. + CertCompressionSpec spec = new CertCompressionSpec(hc, buffer); + + // Update the context. + hc.certDeflater = CompressionAlgorithm.selectDeflater( + spec.compressionAlgorithms); + + if (hc.certDeflater == null) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Ignore, no supported " + + "certificate compression algorithms"); + } + } + // No impact on session resumption. + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java b/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java new file mode 100644 index 000000000000..067a0344c9db --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * 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 sun.security.ssl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.function.Function; +import javax.net.ssl.SSLProtocolException; +import sun.security.ssl.SSLHandshake.HandshakeMessage; +import sun.security.util.Cache; +import sun.security.util.Cache.EqualByteArray; +import sun.security.util.HexDumpEncoder; + +/** + * Pack of the CompressedCertificate handshake message. + */ +final class CompressedCertificate { + + static final SSLConsumer handshakeConsumer = + new CompressedCertConsumer(); + static final HandshakeProducer handshakeProducer = + new CompressedCertProducer(); + + record CompCertCacheKey(EqualByteArray eba, int algId) {} + + /** + * The CompressedCertificate handshake message for TLS 1.3. + */ + static final class CompressedCertMessage extends HandshakeMessage { + + private final int algorithmId; + private final int uncompressedLength; + private final byte[] compressedCert; + + CompressedCertMessage(HandshakeContext context, + int algorithmId, int uncompressedLength, + byte[] compressedCert) { + super(context); + + this.algorithmId = algorithmId; + this.uncompressedLength = uncompressedLength; + this.compressedCert = compressedCert; + } + + CompressedCertMessage(HandshakeContext handshakeContext, + ByteBuffer m) throws IOException { + super(handshakeContext); + + // struct { + // CertificateCompressionAlgorithm algorithm; + // uint24 uncompressed_length; + // opaque compressed_certificate_message<1..2^24-1>; + // } CompressedCertificate; + if (m.remaining() < 9) { + throw new SSLProtocolException( + "Invalid CompressedCertificate message: " + + "insufficient data (length=" + m.remaining() + + ")"); + } + this.algorithmId = Record.getInt16(m); + this.uncompressedLength = Record.getInt24(m); + this.compressedCert = Record.getBytes24(m); + + if (m.hasRemaining()) { + throw handshakeContext.conContext.fatal( + Alert.HANDSHAKE_FAILURE, + "Invalid CompressedCertificate message: " + + "unknown extra data"); + } + } + + @Override + public SSLHandshake handshakeType() { + return SSLHandshake.COMPRESSED_CERTIFICATE; + } + + @Override + public int messageLength() { + return 8 + compressedCert.length; + } + + @Override + public void send(HandshakeOutStream hos) throws IOException { + hos.putInt16(algorithmId); + hos.putInt24(uncompressedLength); + hos.putBytes24(compressedCert); + } + + @Override + public String toString() { + MessageFormat messageFormat = new MessageFormat( + """ + "CompressedCertificate": '{' + "algorithm": "{0}", + "uncompressed_length": {1} + "compressed_certificate_message": [ + {2} + ] + '}'""", + Locale.ENGLISH); + + HexDumpEncoder hexEncoder = new HexDumpEncoder(); + Object[] messageFields = { + CompressionAlgorithm.nameOf(algorithmId), + uncompressedLength, + Utilities.indent(hexEncoder.encode(compressedCert), " ") + }; + + return messageFormat.format(messageFields); + } + } + + /** + * The "CompressedCertificate" handshake message producer for TLS 1.3. + */ + private static final + class CompressedCertProducer implements HandshakeProducer { + + // Prevent instantiation of this class. + private CompressedCertProducer() { + // blank + } + + // Note this is a special producer, which can only be called from + // the CertificateMessage producer. The input 'message' parameter + // represents the Certificate handshake message. + @Override + public byte[] produce(ConnectionContext context, + HandshakeMessage message) throws IOException { + // The producing happens in handshake context only. + HandshakeContext hc = (HandshakeContext) context; + + // Compress the Certificate message. + HandshakeOutStream hos = new HandshakeOutStream(null); + message.send(hos); + byte[] certMsg = hos.toByteArray(); + byte[] compressedCertMsg; + + // First byte is the size of certificate_request_context which + // should be random if present. Don't cache a randomized message. + if (certMsg[0] != 0) { + compressedCertMsg = hc.certDeflater.getValue().apply(certMsg); + } else { + Cache cache = + hc.sslContext.getCompCertCache(); + CompCertCacheKey key = new CompCertCacheKey( + new EqualByteArray(certMsg), hc.certDeflater.getKey()); + compressedCertMsg = cache.get(key); + + if (compressedCertMsg == null) { + compressedCertMsg = + hc.certDeflater.getValue().apply(certMsg); + + if (SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Caching CompressedCertificate message"); + } + + cache.put(key, compressedCertMsg); + } + } + + if (compressedCertMsg == null || compressedCertMsg.length == 0) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No compressed Certificate data"); + } + + CompressedCertMessage ccm = new CompressedCertMessage(hc, + hc.certDeflater.getKey(), certMsg.length, + compressedCertMsg); + + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine( + "Produced CompressedCertificate handshake message", + ccm); + } + + ccm.write(hc.handshakeOutput); + hc.handshakeOutput.flush(); + + // The handshake message has been delivered. + return null; + } + } + + /** + * The "CompressedCertificate" handshake message consumer for TLS 1.3. + */ + private static final class CompressedCertConsumer implements SSLConsumer { + + // Prevent instantiation of this class. + private CompressedCertConsumer() { + // blank + } + + @Override + public void consume(ConnectionContext context, + ByteBuffer message) throws IOException { + // The consuming happens in handshake context only. + HandshakeContext hc = (HandshakeContext) context; + + // clean up this consumer + hc.handshakeConsumers.remove( + SSLHandshake.COMPRESSED_CERTIFICATE.id); + hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id); + + // Parse the handshake message + CompressedCertMessage ccm = new CompressedCertMessage(hc, message); + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine( + "Consuming CompressedCertificate handshake message", + ccm); + } + + // check the compression algorithm + Function inflater = + hc.certInflaters.get(ccm.algorithmId); + if (inflater == null) { + throw hc.conContext.fatal(Alert.BAD_CERTIFICATE, + "Unsupported certificate compression algorithm"); + } + + // decompress + byte[] certificateMessage = inflater.apply(ccm.compressedCert); + + // check the uncompressed length + if (certificateMessage == null || + certificateMessage.length != ccm.uncompressedLength) { + throw hc.conContext.fatal(Alert.BAD_CERTIFICATE, + "Improper certificate compression"); + } + + // Call the Certificate handshake message consumer. + CertificateMessage.t13HandshakeConsumer.consume(hc, + ByteBuffer.wrap(certificateMessage)); + } + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java b/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java new file mode 100644 index 000000000000..3e9ef154424b --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * 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 sun.security.ssl; + +import java.io.ByteArrayOutputStream; +import java.util.AbstractMap; +import java.util.Map; +import java.util.function.Function; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * Enum for TLS certificate compression algorithms. + * This class also defines internally supported inflate/deflate functions. + */ + +enum CompressionAlgorithm { + ZLIB(1); // Currently only ZLIB is supported. + + final int id; + + CompressionAlgorithm(int id) { + this.id = id; + } + + static CompressionAlgorithm nameOf(int id) { + for (CompressionAlgorithm ca : CompressionAlgorithm.values()) { + if (ca.id == id) { + return ca; + } + } + + return null; + } + + // Return the size of a compression algorithms structure in TLS record. + static int sizeInRecord() { + return 2; + } + + // The size of compression/decompression buffer. + private static final int BUF_SIZE = 1024; + + private static final Map> DEFLATORS = + Map.of(ZLIB.id, (input) -> { + try (Deflater deflater = new Deflater(); + ByteArrayOutputStream outputStream = + new ByteArrayOutputStream(input.length)) { + + deflater.setInput(input); + deflater.finish(); + byte[] buffer = new byte[BUF_SIZE]; + + while (!deflater.finished()) { + int compressedSize = deflater.deflate(buffer); + outputStream.write(buffer, 0, compressedSize); + } + + return outputStream.toByteArray(); + } catch (Exception e) { + if (SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("Exception during certificate " + + "compression: ", e); + } + return null; + } + }); + + static Map.Entry> selectDeflater( + int[] compressionAlgorithmIds) { + + for (var entry : DEFLATORS.entrySet()) { + for (int id : compressionAlgorithmIds) { + if (id == entry.getKey()) { + return new AbstractMap.SimpleImmutableEntry<>(entry); + } + } + } + + return null; + } + + private static final Map> INFLATORS = + Map.of(ZLIB.id, (input) -> { + try (Inflater inflater = new Inflater(); + ByteArrayOutputStream outputStream = + new ByteArrayOutputStream(input.length)) { + + inflater.setInput(input); + byte[] buffer = new byte[BUF_SIZE]; + + while (!inflater.finished()) { + int decompressedSize = inflater.inflate(buffer); + + if (decompressedSize == 0) { + if (inflater.needsDictionary()) { + if (SSLLogger.isOn() + && SSLLogger.isOn( + SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("Compressed input " + + "requires a dictionary"); + } + + return null; + } + + if (inflater.needsInput()) { + if (SSLLogger.isOn() + && SSLLogger.isOn( + SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning( + "Incomplete compressed input"); + } + + return null; + } + + // Else just break the loop. + break; + } + + outputStream.write(buffer, 0, decompressedSize); + + // Bound the memory usage. + if (outputStream.size() + > SSLConfiguration.maxHandshakeMessageSize) { + if (SSLLogger.isOn() + && SSLLogger.isOn( + SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("The size of the " + + "uncompressed certificate message " + + "exceeds maximum allowed size of " + + SSLConfiguration.maxHandshakeMessageSize + + " bytes; compressed size: " + + input.length); + } + + return null; + } + } + + return outputStream.toByteArray(); + } catch (Exception e) { + if (SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning( + "Exception during certificate decompression: ", + e); + } + return null; + } + }); + + static Map> getInflaters() { + return INFLATORS; + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java index 54a2650c0589..fbf2c00bbb40 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.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 @@ -33,6 +33,7 @@ import java.security.CryptoPrimitive; import java.util.*; import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.function.Function; import javax.crypto.SecretKey; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLHandshakeException; @@ -131,6 +132,10 @@ abstract class HandshakeContext implements ConnectionContext { List peerRequestedSignatureSchemes; List peerRequestedCertSignSchemes; + // CertificateCompressionAlgorithm + Map> certInflaters; + Map.Entry> certDeflater; + // Known authorities X500Principal[] peerSupportedAuthorities = null; diff --git a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java index b5f1eff179cc..3384bf5f0896 100644 --- a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java @@ -73,6 +73,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport { SSLHandshake.ENCRYPTED_EXTENSIONS.id, HANDSHAKE, SSLHandshake.CERTIFICATE_REQUEST.id, HANDSHAKE, SSLHandshake.CERTIFICATE.id, HANDSHAKE, + SSLHandshake.COMPRESSED_CERTIFICATE.id, HANDSHAKE, SSLHandshake.CERTIFICATE_VERIFY.id, HANDSHAKE, SSLHandshake.FINISHED.id, HANDSHAKE, SSLHandshake.NEW_SESSION_TICKET.id, ONE_RTT); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index a1cc3ee112f9..fdeb94bb4969 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -34,7 +34,9 @@ import java.util.stream.Collectors; import javax.net.ssl.*; import sun.security.provider.certpath.AlgorithmChecker; +import sun.security.ssl.CompressedCertificate.CompCertCacheKey; import sun.security.ssl.SSLAlgorithmConstraints.SIGNATURE_CONSTRAINTS_MODE; +import sun.security.util.Cache; import sun.security.validator.Validator; /** @@ -73,6 +75,10 @@ public abstract class SSLContextImpl extends SSLContextSpi { private final ReentrantLock contextLock = new ReentrantLock(); + // Avoid compressing local certificates repeatedly for every handshake. + private final Cache compCertCache = + Cache.newSoftMemoryCache(12); + SSLContextImpl() { ephemeralKeyManager = new EphemeralKeyManager(); clientCache = new SSLSessionContextImpl(false); @@ -225,6 +231,10 @@ EphemeralKeyManager getEphemeralKeyManager() { return ephemeralKeyManager; } + Cache getCompCertCache() { + return compCertCache; + } + // Used for DTLS in server mode only. HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) { if (helloCookieManagerBuilder == null) { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java index aacb94207484..b13edc0359cb 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.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 @@ -270,6 +270,27 @@ enum SSLExtension implements SSLStringizer { // Extensions defined in RFC 7924 (TLS Cached Information Extension) CACHED_INFO (0x0019, "cached_info"), + // Extensions defined in RFC 8879 (TLS Certificate Compression) + CH_COMPRESS_CERTIFICATE (0x001B, "compress_certificate", + SSLHandshake.CLIENT_HELLO, + ProtocolVersion.PROTOCOLS_OF_13, + CompressCertExtension.chNetworkProducer, + CompressCertExtension.chOnLoadConsumer, + null, + null, + null, + CompressCertExtension.ccStringizer), + + CR_COMPRESS_CERTIFICATE (0x001B, "compress_certificate", + SSLHandshake.CERTIFICATE_REQUEST, + ProtocolVersion.PROTOCOLS_OF_13, + CompressCertExtension.crNetworkProducer, + CompressCertExtension.crOnLoadConsumer, + null, + null, + null, + CompressCertExtension.ccStringizer), + // Extensions defined in RFC 5077 (TLS Session Resumption without Server-Side State) CH_SESSION_TICKET (0x0023, "session_ticket", SSLHandshake.CLIENT_HELLO, diff --git a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java index 7c78f6c30052..2c6b58bafa51 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -370,7 +370,22 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { }), // RFC 8879 - TLS Certificate Compression - COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate"), + @SuppressWarnings({"unchecked", "rawtypes"}) + COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate", + (new Map.Entry[] { + new SimpleImmutableEntry<>( + CompressedCertificate.handshakeConsumer, + ProtocolVersion.PROTOCOLS_OF_13 + ) + }), + (new Map.Entry[] { + // Note that the producing of this message is delegated to + // CertificateMessage producer. + new SimpleImmutableEntry<>( + CertificateMessage.t13HandshakeProducer, + ProtocolVersion.PROTOCOLS_OF_13 + ) + })), // RFC 8870 - Encrypted Key Transport for DTLS/Secure RTP EKT_KEY ((byte)0x1A, "ekt_key"), diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index f603cc229497..cef2f43526a8 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.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,13 +28,13 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; -import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.TimeUnit; @@ -77,10 +77,10 @@ public final class SSLSocketImpl /** * ERROR HANDLING GUIDELINES * (which exceptions to throw and catch and which not to throw and catch) - * + *

* - if there is an IOException (SocketException) when accessing the * underlying Socket, pass it through - * + *

* - do not throw IOExceptions, throw SSLExceptions (or a subclass) */ @@ -454,12 +454,12 @@ private void startHandshake(boolean resumable) throws IOException { if (!conContext.isNegotiated) { readHandshakeRecord(); } - } catch (InterruptedIOException iioe) { + } catch (SocketTimeoutException e) { if(resumable){ - handleException(iioe); + handleException(e); } else{ throw conContext.fatal(Alert.HANDSHAKE_FAILURE, - "Couldn't kickstart handshaking", iioe); + "Couldn't kickstart handshaking", e); } } catch (SocketException se) { handleException(se); @@ -1427,7 +1427,7 @@ private int readHandshakeRecord() throws IOException { return 0; } } catch (SSLException | - InterruptedIOException | SocketException se) { + SocketTimeoutException | SocketException se) { // Don't change exception in case of timeouts or interrupts // or SocketException. throw se; @@ -1486,7 +1486,7 @@ private ByteBuffer readApplicationRecord( return buffer; } } catch (SSLException | - InterruptedIOException | SocketException se) { + SocketTimeoutException | SocketException se) { // Don't change exception in case of timeouts or interrupts // or SocketException. throw se; @@ -1677,40 +1677,23 @@ private void handleException(Exception cause) throws IOException { SSLLogger.warning("handling exception", cause); } - // Don't close the Socket in case of timeouts or interrupts. - if (cause instanceof InterruptedIOException) { - throw (IOException)cause; - } - - // need to perform error shutdown - boolean isSSLException = (cause instanceof SSLException); - Alert alert; - if (isSSLException) { - if (cause instanceof SSLHandshakeException) { - alert = Alert.HANDSHAKE_FAILURE; - } else { - alert = Alert.UNEXPECTED_MESSAGE; - } - } else { - if (cause instanceof IOException) { - alert = Alert.UNEXPECTED_MESSAGE; - } else { - // RuntimeException - alert = Alert.INTERNAL_ERROR; - } - } - - if (cause instanceof SocketException) { - try { - throw conContext.fatal(alert, cause); - } catch (Exception e) { - // Just delivering the fatal alert, re-throw the socket exception instead. - } - - throw (SocketException)cause; - } - - throw conContext.fatal(alert, cause); + throw switch (cause) { + // Don't close the Socket in case of timeouts. + case SocketTimeoutException ste -> ste; + // Send TLS alert with "fatal", then throw the socket exception. + case SocketException se -> { + try { + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, se); + } catch (Exception _) { + } + yield se; + } + case SSLHandshakeException sslhe -> + conContext.fatal(Alert.HANDSHAKE_FAILURE, sslhe); + case IOException ioe -> + conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); + default -> conContext.fatal(Alert.INTERNAL_ERROR, cause); + }; } private Plaintext handleEOF(EOFException eofe) throws IOException { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java index fd9c4b171e75..fc3d9733150b 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.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. * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,10 +27,10 @@ package sun.security.ssl; import java.io.EOFException; -import java.io.InterruptedIOException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.util.ArrayList; @@ -180,7 +180,7 @@ Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset, if (plaintext == null) { plaintext = decodeInputRecord(); } - } catch(InterruptedIOException e) { + } catch (SocketTimeoutException e) { // do not clean header and recordBody in case of Socket Timeout cleanInBuffer = false; throw e; diff --git a/src/java.base/share/classes/sun/security/ssl/SSLTransport.java b/src/java.base/share/classes/sun/security/ssl/SSLTransport.java index 50bff1e6d218..02551b4a8c1a 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLTransport.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLTransport.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 @@ -27,8 +27,8 @@ import java.io.EOFException; import java.io.IOException; -import java.io.InterruptedIOException; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import javax.crypto.AEADBadTagException; import javax.crypto.BadPaddingException; @@ -138,7 +138,7 @@ static Plaintext decode(TransportContext context, } catch (EOFException eofe) { // rethrow EOFException, the call will handle it if needed. throw eofe; - } catch (InterruptedIOException | SocketException se) { + } catch (SocketTimeoutException | SocketException se) { // don't close the Socket in case of timeouts or interrupts or SocketException. throw se; } catch (IOException ioe) { diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index 6980c216697d..4bd2b0a059f5 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, 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 @@ -1461,6 +1461,11 @@ public void consume(ConnectionContext context, chc.handshakeConsumers.put( SSLHandshake.CERTIFICATE_REQUEST.id, SSLHandshake.CERTIFICATE_REQUEST); + if (chc.certInflaters != null && !chc.certInflaters.isEmpty()) { + chc.handshakeConsumers.put( + SSLHandshake.COMPRESSED_CERTIFICATE.id, + SSLHandshake.COMPRESSED_CERTIFICATE); + } chc.handshakeConsumers.put( SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); 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 597652022ced..ce903a3d16cf 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 @@ 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 DNSName(DerValue derValue) throws IOException { * @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(); + } + + // 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"); } - 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 *"); - } - } 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"); + + // 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"); } - //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"); + // 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"); + } } } + this.name = name; } diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 18d64b3a4c2b..6c079c268b16 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 4621ab588d19..e19ba280fa7b 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 3b24a784491f..51c2d8b85731 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 4830fedb97b5..e6aebead2120 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 3ad148b0be55..96d3050f5270 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]; + /* 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; + /* - * 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. + * Search down the target hash chain for a cell whose + * 32 bit hash matches the hashed name. */ - 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; + 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; } - 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; + 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; } - - /* Add slash and try once more */ - name[ulen++] = '/'; - name[ulen] = '\0'; - hsh = hash_append(hsh, '/'); - idx = zip->table[hsh % zip->tablelen]; - addSlash = JNI_FALSE; + 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 9825202fc7bd..8cfe0b261f5c 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 cd253edde601..2f163cf27f1f 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 f5025b9f4886..5ed99f256d80 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.desktop/macosx/classes/sun/lwawt/LWListPeer.java b/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java index e2f262019194..001a44ebf8a7 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.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.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 @@ public void removeAll() { @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 @@ public void makeVisible(final int index) { @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/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index 5be7f70b981c..4315abe61977 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.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 @@ -188,10 +188,6 @@ public void propertyChange(PropertyChangeEvent e) { // Do send check box state changes to native side if (thisRole == AccessibleRole.CHECK_BOX) { - if (!Objects.equals(newValue, oldValue)) { - valueChanged(ptr); - } - // Notify native side to handle check box style menuitem if (parentRole == AccessibleRole.POPUP_MENU && newValue != null && ((AccessibleState)newValue) == AccessibleState.FOCUSED) { @@ -201,23 +197,12 @@ public void propertyChange(PropertyChangeEvent e) { // Do send radio button state changes to native side if (thisRole == AccessibleRole.RADIO_BUTTON) { - if (newValue != null && !newValue.equals(oldValue)) { - valueChanged(ptr); - } - // Notify native side to handle radio button style menuitem if (parentRole == AccessibleRole.POPUP_MENU && newValue != null && ((AccessibleState)newValue) == AccessibleState.FOCUSED) { menuItemSelected(ptr); } } - - // Do send toggle button state changes to native side - if (thisRole == AccessibleRole.TOGGLE_BUTTON) { - if (!Objects.equals(newValue, oldValue)) { - valueChanged(ptr); - } - } } else if (name.equals(ACCESSIBLE_NAME_PROPERTY)) { //for now trigger only for JTabbedPane. if (e.getSource() instanceof JTabbedPane) { @@ -227,7 +212,10 @@ public void propertyChange(PropertyChangeEvent e) { AccessibleRole thisRole = accessible.getAccessibleContext() .getAccessibleRole(); if (thisRole == AccessibleRole.SLIDER || - thisRole == AccessibleRole.PROGRESS_BAR) { + thisRole == AccessibleRole.PROGRESS_BAR || + thisRole == AccessibleRole.CHECK_BOX || + thisRole == AccessibleRole.RADIO_BUTTON || + thisRole == AccessibleRole.TOGGLE_BUTTON ) { valueChanged(ptr); } } 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 45e8f981f501..40f9f50a7d77 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 @@ - (BOOL)performAccessibleAction:(int)index 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/share/classes/com/sun/imageio/stream/StreamCloser.java b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 7de400ad199e..29aaed7d9e35 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 7f021dcdb853..21358efa3f38 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 @@ protected class FlipBufferStrategy extends BufferStrategy { * {@code true}. * @see #createBuffers(int, BufferCapabilities) */ - @SuppressWarnings("removal") protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { @@ -8129,7 +8128,6 @@ boolean transferFocus(boolean clearOnFailure) { 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 25fe72e1787d..c919374a85c7 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 7eaa14133c5c..2d6edaca544d 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 @@ public SubRegistry(ServiceRegistry registry, Class category) { 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 58b23569a92f..0fd2da05d606 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 f762eb899257..ea4dcf54f321 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 UnmodifiableAttributeSet(AttributeSet attributeSet) { 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 SynchronizedAttributeSet(AttributeSet attributeSet) { 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 2f0eafb9f791..154b492de848 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 Date getValue() { * @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 boolean equals(Object object) { * 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 int hashCode() { * 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 102786da27bc..2abd6e6322a2 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 fd48a600ee3f..4c291999e02a 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 int getValue() { * semantics of enumeration values is the same object as this enumeration * value. */ + @Override public Object clone() { return this; } @@ -153,6 +154,7 @@ public Object clone() { * 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 int hashCode() { /** * 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 4ad4c8634aa0..6800b45a3495 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 @@ protected HashAttributeSet(AttributeSet attributes, Class interfaceName) { * {@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 Attribute get(Class category) { * @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 boolean add(Attribute attribute) { * @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 boolean remove(Class category) { * @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 boolean remove(Attribute attribute) { * @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 boolean containsKey(Class category) { * @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 boolean containsValue(Attribute attribute) { * {@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 boolean addAll(AttributeSet attributes) { * * @return the number of attributes in this attribute set */ + @Override public int size() { return attrMap.size(); } @@ -402,6 +410,7 @@ public int size() { * @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 Attribute[] toArray() { * @throws UnmodifiableSetException if this attribute set does not support * the {@code clear()} operation */ + @Override public void clear() { attrMap.clear(); } @@ -423,6 +433,7 @@ public void clear() { * * @return {@code true} if this attribute set contains no attributes */ + @Override public boolean isEmpty() { return attrMap.isEmpty(); } @@ -438,6 +449,7 @@ public boolean isEmpty() { * @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 boolean equals(Object object) { * * @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 f6dbee3aa5a6..b6846ff72711 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 int getValue() { * @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 boolean equals(Object object) { * 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 int hashCode() { * 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 63535fba93eb..ce22602f4d55 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 95a07655f033..958d255b2965 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 fd2d4dc4694b..a456eac07b6e 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 8ffae65a0d23..ffb1fab3619d 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 boolean lessThanOrEquals(ResolutionSyntax other) { * @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 boolean equals(Object object) { /** * Returns a hash code value for this resolution attribute. */ + @Override public int hashCode() { return(((crossFeedResolution & 0x0000FFFF)) | ((feedResolution & 0x0000FFFF) << 16)); @@ -286,6 +288,7 @@ public int hashCode() { * 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 6df67ef90ca4..8088cfcd7434 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 int next(int x) { * @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 boolean equals(Object object) { * 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 int hashCode() { * 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 9ff772bc30d6..056031b52f28 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 String toString(int units, String unitsName) { * @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 boolean equals(Object object) { /** * 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 int hashCode() { * 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 9a343bc8af2c..2c49a11b250b 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 Locale getLocale() { * * @return a hashcode value for this object */ + @Override public int hashCode() { return value.hashCode() ^ locale.hashCode(); } @@ -131,6 +132,7 @@ public int hashCode() { * @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 boolean equals(Object object) { * * @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 10545df71fd4..b3e604283f7e 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 URI getURI() { * * @return a hashcode value for this object */ + @Override public int hashCode() { return uri.hashCode(); } @@ -100,6 +101,7 @@ public int hashCode() { * @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 boolean equals(Object object) { * * @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 87d6a41c2b0f..9a7e67913ffc 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 @@ void setPaintingChild(Component paintingChild) { 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 7245820c289a..58a74def3b6d 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 @@ static Popup getMediumWeightPopup(Component owner, Component contents, /** * 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 ab21e5559199..9901ef04a473 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 @@ private Image _getOffscreenBuffer(Component c, int proposedWidth, int proposedHe // 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 4c3d02098236..58a4b384ccfd 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 @@ private int getPopupFitWidth(Rectangle popupRectInScreen, Component invoker){ // 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/sun/awt/geom/AreaOp.java b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java index 1d0e6df3734b..65f7dbf11ebf 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 @@ private 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 int compare(Edge o1, Edge o2) { } }; + 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 @@ private Vector pruneEdges(Vector edges) { 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 @@ private Vector pruneEdges(Vector edges) { 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 83986b887779..7cdb45e5a223 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 int compareTo(Curve that, double[] yrange) { 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 double refineTforY(double t0, double yt0, double y0) { 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/windows/classes/sun/awt/windows/WWindowPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java index f028e0fbec59..9c1c7665f4b0 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 c65bfb9f2f96..a48defd471d0 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 f7ea013412d5..b9771e55b447 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 fdff5d84189f..77bb54fa5ba0 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.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 StartTlsResponseImpl() {} * 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 void setEnabledCipherSuites(String[] suites) { * @param verifier The non-null hostname verifier callback. * @see #negotiate */ + @Override public void setHostnameVerifier(HostnameVerifier verifier) { this.verifier = verifier; } @@ -165,6 +161,7 @@ public void setHostnameVerifier(HostnameVerifier verifier) { * @see #setEnabledCipherSuites * @see #setHostnameVerifier */ + @Override public SSLSession negotiate() throws IOException { return negotiate(null); @@ -200,9 +197,10 @@ public SSLSession negotiate() throws IOException { * @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 SSLSession negotiate(SSLSocketFactory factory) throws IOException { SSLPeerUnverifiedException verifExcep = null; try { if (verify(hostname, sslSession)) { - isClosed = false; return sslSession; } } catch (SSLPeerUnverifiedException e) { @@ -232,18 +229,18 @@ public SSLSession negotiate(SSLSocketFactory factory) throws IOException { } 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 SSLSession negotiate(SSLSocketFactory factory) throws IOException { * @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 void close() throws IOException { 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 void setConnection(Connection ldapConnection, String hostname) { * 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 @@ private SSLSocket startHandshake(SSLSocketFactory factory) 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 @@ private boolean verify(String hostname, SSLSession session) "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/HttpRequestBuilderImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java index ef0e2b152bb2..c39edf878c94 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, 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 @@ -145,7 +145,7 @@ public HttpRequestBuilderImpl header(String name, String value) { @Override public HttpRequestBuilderImpl headers(String... params) { requireNonNull(params); - if (params.length == 0 || params.length % 2 != 0) { + if (params.length % 2 != 0) { throw newIAE("wrong number, %d, of parameters", params.length); } for (int i = 0; i < params.length; i += 2) { 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 c662983d0af4..e7dec5a6963b 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 @@ final class Reader extends SubscriberWrapper implements FlowTube.TubeSubscriber 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 @@ protected SchedulingAction enterScheduling() { return enterReadScheduling(); } + @Override + public boolean closing() { + return closeNotifyReceived(); + } + public final String dbgString() { return "SSL Reader(" + tubeName + ")"; } @@ -505,7 +510,7 @@ else if (this.completing) { 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 @@ else if (this.completing) { 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 @@ EngineResult unwrapBuffer(ByteBuffer src) throws IOException { 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 @@ private void processData() { 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 @@ private void resumeActivity() { 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 @@ private boolean doHandshake(EngineResult r, int caller) { break; default: throw new InternalError("Unexpected handshake status:" - + r.handshakeStatus()); + + handshakeStatus); } return true; } @@ -1182,34 +1190,20 @@ boolean trySetALPN() { 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 b9e1def58e04..013ed31c8c19 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 void addData(ByteBuffer l) { } 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 1f6e98e50e85..f04f28ae1344 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 byte[] stringToKey(char[] password, String salt, byte[] s2kparams) 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 @@ private static byte[] PBKDF2(char[] secret, byte[] salt, 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 cb9e42b2deeb..5af0517f883f 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 byte[] stringToKey(char[] password, String salt, byte[] s2kparams) 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 @@ private static byte[] PBKDF2(char[] secret, byte[] salt, 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 da3278145924..260f30bd0003 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 @@ static byte[] charToUtf16(char[] chars) { 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 e3f25731e6df..d6ac228b9825 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 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 @@ * 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 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, 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 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, 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 c2faf90ce2e1..f62a290557db 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 @@ * 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 XPathExpression compile(String expression) // 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 773c573c201d..776fd544bfb5 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.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 static Lint instance(Context context) { */ 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 Lint suppress(LintCategory... lc) { 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 @@ protected Lint(Context context) { 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 @@ protected Lint(Lint other) { 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 @@ private EnumSet getDefaults() { @Override public String toString() { initializeRootIfNeeded(); - return "Lint:[enable" + values + ",suppress" + suppressedValues + "]"; + return "Lint:[enable" + values + ",suppress" + suppressedValues + ",deprecated=" + withinDeprecated + "]"; } /** @@ -443,6 +437,34 @@ public static EnumSet newEmptySet() { 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 boolean isEnabled(LintCategory lc) { } /** - * 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 boolean isSuppressed(LintCategory lc) { * 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 9b78a02170cc..a44b2f96867a 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 @@ Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContex 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 @@ Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContex } /** 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 @@ private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) { 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 89ae68e85bad..3a3d9cd99e01 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 @@ -3241,7 +3241,7 @@ public void visitLambda(final JCLambda that) { 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 void visitLambda(final JCLambda that) { 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 @@ ResultInfo lambdaBodyResult(JCLambda that, Type descriptor, ResultInfo resultInf * (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 @@ void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkCon 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 d16bbf2a2eee..89422ac46717 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 @@ JCLambda attribSpeculativeLambda(JCLambda that, Env env, ResultInfo 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 @@ JCLambda attribSpeculativeLambda(JCLambda that, Env env, ResultInfo 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 void visitLambda(JCLambda tree) { 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 f5e9bfcd7a81..6021dbd7057d 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 Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInte //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 269d2f5de62c..56dfd395aed0 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 JavaCompiler(Context context) { 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 boolean exists() { */ 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 @@ protected boolean shouldStop(CompileState cs) { 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 int errorCount() { * 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/parser/TextBlockSupport.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java index d099ceadba00..5112849d45fe 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.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 @@ -56,8 +56,8 @@ static Set checkWhitespace(String string) { // No need to check indentation if opting out (last line is empty.) char lastChar = string.charAt(string.length() - 1); boolean optOut = lastChar == '\n' || lastChar == '\r'; - // Split string based at line terminators. - String[] lines = string.split("\\R"); + // Split string using JLS text block line terminators: CRLF, CR, or LF. + String[] lines = string.split("\\r\\n|\\r|\\n"); int length = lines.length; // Extract last line. String lastLine = length == 0 ? "" : lines[length - 1]; 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 58a5333ce4c1..1ae2c9de35a0 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 328183c0cb39..aed42f7b2b25 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 enum DiagnosticFlag { * 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 b061d2283a05..dd4e14d373dd 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 final void reportWithLint(JCDiagnostic diag, Lint lint) { } // 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 @@ protected int getDefaultMaxWarnings() { */ 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 void clear() { lintWarnings.clear(); nerrors = 0; nwarnings = 0; + nonLintWarnings = 0; nsuppressederrors = 0; nsuppressedwarns = 0; while (diagnosticHandler.prev != null) @@ -989,7 +986,7 @@ protected void writeDiagnostic(JCDiagnostic diag) { nwarnings++; Optional.of(diag) .map(JCDiagnostic::getLintCategory) - .ifPresent(lintWarnings::add); + .ifPresentOrElse(lintWarnings::add, () -> nonLintWarnings++); break; case ERROR: nerrors++; @@ -1129,6 +1126,7 @@ public void rawWarning(int pos, String msg) { } prompt(); nwarnings++; + nonLintWarnings++; warnWriter.flush(); } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java index 0ad7ba1651d1..05b5f6f69f4b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java @@ -74,9 +74,6 @@ public static class X64 { debug("AVX=%b; AVX2=%b; AVX512F=%b; AVX512DQ=%b", SUPPORTS_AVX, SUPPORTS_AVX2, SUPPORTS_AVX512F, SUPPORTS_AVX512DQ); - assert SUPPORTS_AVX512F == (VectorShape.getMaxVectorBitSize(int.class) == 512); - assert SUPPORTS_AVX2 == (VectorShape.getMaxVectorBitSize(byte.class) >= 256); - assert SUPPORTS_AVX == (VectorShape.getMaxVectorBitSize(float.class) >= 256); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java index 823cebd85a92..59697733d86e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java @@ -31,6 +31,7 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; +import java.util.Locale; import java.util.function.IntFunction; import static jdk.incubator.vector.Util.requires; @@ -141,7 +142,7 @@ public String symbolName(Operator op, VectorSpecies vspecies) { String elemType = (vspecies.elementType() == float.class ? "f" : ""); boolean isFloatVector64 = (vspecies.elementType() == float.class) && (vspecies.length() == 2); // FloatVector64 or FloatVectorMax int vlen = (isFloatVector64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors - return String.format("__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix); + return String.format(Locale.ROOT, "__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix); } @Override @@ -214,7 +215,7 @@ public String symbolName(Operator op, VectorSpecies vspecies) { boolean isFloatVector64 = (vspecies.elementType() == float.class) && (vspecies.length() == 2); // FloatVector64 or FloatVectorMax int vlen = (isFloatVector64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors boolean isShapeAgnostic = isRISCV64() || (isAARCH64() && vspecies.vectorBitSize() > 128); - return String.format("%s%s%s_%s%s", op.operatorName(), + return String.format(Locale.ROOT, "%s%s%s_%s%s", op.operatorName(), (vspecies.elementType() == float.class ? "f" : "d"), (isShapeAgnostic ? "x" : Integer.toString(vlen)), precisionLevel(op), diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java index 8f5fec1e4b95..90511db8053a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, 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 @@ -48,7 +48,7 @@ * in documentation comments. * * Taglets invoked by the standard doclet must return strings from - * {@link Taglet#toString(List,Element) Taglet.toString} as follows: + * {@link Taglet#toString(List,Element,java.net.URI) Taglet.toString} as follows: * *

*
Inline Tags diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java index 1ad67a89fefc..ec079047dfa4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.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 @@ -25,6 +25,7 @@ package jdk.javadoc.doclet; +import java.net.URI; import java.util.List; import java.util.Set; @@ -34,7 +35,7 @@ /** * The interface for a custom taglet supported by doclets such as - * the {@link jdk.javadoc.doclet.StandardDoclet standard doclet}. + * the {@linkplain StandardDoclet standard doclet}. * Custom taglets are used to handle custom tags in documentation * comments; custom tags can be instantiated individually as either * block tags, which appear at the end of a comment, @@ -55,10 +56,10 @@ * {@link #isInlineTag() isInlineTag}, to determine the characteristics * of the tags supported by the taglet. *
  • As appropriate, the doclet calls the - * {@link #toString(List,Element) toString} method on the taglet object, - * giving it a list of tags and the element for which the tags are part - * of the element's documentation comment, from which the taglet can - * determine the string to be included in the documentation. + * {@link #toString(List,Element,URI) toString} method on the taglet object, + * giving it a list of tags, the element whose documentation comment contains + * the tags, and the root URI of the generated output, from which the taglet + * can determine the string to be included in the documentation. * The doclet will typically specify any requirements on the contents of * the string that is returned. * @@ -126,25 +127,70 @@ default boolean isBlockTag() { default void init(DocletEnvironment env, Doclet doclet) { } /** - * Returns the string representation of a series of instances of - * this tag to be included in the generated output. + * Returns the string representation of the specified instances of this tag + * to be included in the generated output. * - *

    If this taglet supports {@link #isInlineTag inline} tags, it will + *

    If this taglet supports {@link #isInlineTag inline} tags, this method will * be called once per instance of the inline tag, each time with a singleton list. * If this taglet supports {@link #isBlockTag block} tags, it will be called once * for each comment containing instances of block tags, with a list of all the instances * of the block tag in that comment. * + * @apiNote Taglets that do not need the root URI of the generated output may + * implement this method only. Taglets that require the root URI to link to other + * doclet-generated resources should override {@link #toString(List, Element, URI)}, + * and optionally throw an exception in the implementation of this method. + * * @param tags the list of instances of this tag * @param element the element to which the enclosing comment belongs * @return the string representation of the tags to be included in * the generated output - * + * @throws UnsupportedOperationException if {@link #toString(List, Element, URI)} + * should be invoked instead * @see User-Defined Taglets * for the Standard Doclet + * @see #toString(List, Element, URI) */ String toString(List tags, Element element); + /** + * Returns the string representation of the specified instances of this tag + * to be included in the generated output. + * + *

    If this taglet supports {@link #isInlineTag inline} tags, this method will + * be called once per instance of the inline tag, each time with a singleton list. + * If this taglet supports {@link #isBlockTag block} tags, it will be called once + * for each comment containing instances of block tags, with a list of all the instances + * of the block tag in that comment. + * + *

    The {@code docRoot} argument identifies the root of the generated output + * as seen by the current resource, and may be used to {@linkplain URI#resolve(String) + * resolve} links to other resources generated by the doclet. + * + * @apiNote The exact form of {@code docRoot} is doclet-specific. For the + * {@linkplain StandardDoclet standard doclet}, it is a relative URI from + * the current resource to the root directory of the generated output. + * Taglets intended for use with other doclets should check the validity + * of the {@code docRoot} argument as appropriate. + * + * @implSpec The default implementation invokes {@link #toString(List, Element) + * toString(tags, element)}. + * + * @param tags the list of instances of this tag + * @param element the element to which the enclosing comment belongs + * @param docRoot the root URI of the generated output + * @return the string representation of the tags to be included in + * the generated output + * @throws IllegalArgumentException if {@code docRoot} is not a valid URI + * @see User-Defined Taglets + * for the Standard Doclet + * @see #toString(List, Element) + * @since 27 + */ + default String toString(List tags, Element element, URI docRoot) { + return toString(tags, element); + } + /** * The kind of location in which a tag may be used. */ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 86ac3a892fd1..594c36c4af2a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -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 @@ -243,12 +243,8 @@ protected HtmlDocletWriter(HtmlConfiguration configuration, DocPath path, boolea if (generating) { writeGenerating(); } - CURRENT_PATH.set(path.getPath()); } - /** Temporary workaround to share current path with taglets, see 8373909 */ - public static final ThreadLocal CURRENT_PATH = new ThreadLocal<>(); - /** * The top-level method to generate and write the page represented by this writer. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java index d1884c53ccfc..8d54aa0585b4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, 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 @@ -25,6 +25,7 @@ package jdk.javadoc.internal.doclets.formats.html.taglets; +import java.net.URI; import java.util.List; import java.util.Set; @@ -70,7 +71,8 @@ public String getName() { @Override public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) { Content output = tagletWriter.getOutputInstance(); - output.add(RawHtml.of(userTaglet.toString(List.of(tag), element))); + URI pathToRoot = getPathToRoot(tagletWriter); + output.add(RawHtml.of(userTaglet.toString(List.of(tag), element, pathToRoot))); return output; } @@ -80,11 +82,17 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) { var utils = tagletWriter.utils; List tags = utils.getBlockTags(holder, getName()); if (!tags.isEmpty()) { - String tagString = userTaglet.toString(tags, holder); + URI pathToRoot = getPathToRoot(tagletWriter); + String tagString = userTaglet.toString(tags, holder, pathToRoot); if (tagString != null) { output.add(RawHtml.of(tagString)); } } return output; } + + private URI getPathToRoot(TagletWriter tagletWriter) { + var path = tagletWriter.htmlWriter.pathToRoot.getPath(); + return URI.create(path.isEmpty() || path.endsWith("/") ? path : path + "/"); + } } 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 e24fcd571568..c6d878fa8fd6 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 97d4676e6a50..dcf673df8bc9 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 @@ /** * 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 92c40823bbb6..b980e7659819 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 @@ /** * 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 a00a71b3531e..cc1426025d05 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 @@ /** * 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/internal/consumer/ParserFactory.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java index e7dd234ca8d0..c973dadb3b7f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java @@ -132,9 +132,12 @@ private Parser createPrimitiveParser(Type type, boolean event) throws IOExceptio case "short" -> new ShortParser(); case "byte" -> new ByteParser(); case "java.lang.String" -> { - ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); - ConstantLookup lookup = new ConstantLookup(pool, type); - constantLookups.put(type.getId(), lookup); + ConstantLookup lookup = constantLookups.get(type.getId()); + if (lookup == null) { + ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); + lookup = new ConstantLookup(pool, type); + constantLookups.put(type.getId(), lookup); + } yield new StringParser(lookup, event); } default -> throw new IOException("Unknown primitive type " + type.getName()); 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 812525e0ff4b..2ba7aa5db30a 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 26d65f8061c7..d346e241035a 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.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java index 9f61cc3f3582..4a1ef30b9cf6 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 @@ * 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 @@ * 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 @@ * {@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 @@ * {@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 @@ * 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/test/docs/ProblemList.txt b/test/docs/ProblemList.txt index d856f9c955ee..6d496f62a218 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 4cdb342d45c8..dcc025bdbf5b 100644 --- a/test/hotspot/gtest/concurrentTestRunner.inline.hpp +++ b/test/hotspot/gtest/concurrentTestRunner.inline.hpp @@ -86,7 +86,7 @@ class ConcurrentTestRunner { 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 e61ce43fdb61..344f32d5ec86 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 08df547585ab..01e512b6b223 100644 --- a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp @@ -87,7 +87,7 @@ class G1TestSubTask : public G1AbstractSubTask { ~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 91951b35405a..2236b4e83aaf 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -69,7 +69,7 @@ class G1FindCardsInRange : public StackObj { } ~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 b343e7fc47fe..61115fe9ea03 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -486,7 +486,7 @@ class OopStorageTestBlockRelease : public OopStorageTestWithAllocation { 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 3f049eda6eac..72dd61c5cf43 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 @@ class OopStorageParIterPerf::Task : public WorkerTask { } ~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 18cf3b3333f9..d395bd27db2e 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp @@ -555,7 +555,7 @@ class ShenandoahMarkBitMapTest: public ::testing::Test { 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 77cc3ee1f75f..5a50d0505110 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 93cace9c689d..59045b3a7afb 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 2634b8dac770..61502f37d805 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 8ac92f666657..2bc644d9d0c6 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 9773aa2d027d..abd108a698fd 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 4c9bf67997b4..cfa70919bedb 100644 --- a/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp +++ b/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp @@ -42,7 +42,7 @@ class TestMap { _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 @@ class FeederBuffer { } ~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 6ca6b68baa3c..c4ddca624aa9 100644 --- a/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp +++ b/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp @@ -100,7 +100,7 @@ class SparseArray : public StackObj { } ~SparseArray() { - FREE_C_HEAP_ARRAY(T, _slots); + FREE_C_HEAP_ARRAY(_slots); } T at(int i) { return _slots[i]; } @@ -165,4 +165,3 @@ class SparseArray : public StackObj { }; #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 c8711004f105..23575fe2c134 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 c37f5772a5d3..6bf42c6f0445 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/runtime/test_mutex.cpp b/test/hotspot/gtest/runtime/test_mutex.cpp index 2ed7b1b3a34b..64b7a5207d7f 100644 --- a/test/hotspot/gtest/runtime/test_mutex.cpp +++ b/test/hotspot/gtest/runtime/test_mutex.cpp @@ -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 @@ -323,11 +323,12 @@ TEST_VM_ASSERT_MSG(MutexSafepoint, possible_safepoint_lock, ".* Possible safepoint reached by thread that does not allow it") { JavaThread* thread = JavaThread::current(); ThreadInVMfromNative in_native(thread); - MutexLocker ml(new Mutex(Mutex::nosafepoint, "SpecialTest_lock"), + MutexLocker ml(new Mutex(Mutex::nosafepoint-2, "SpecialTest_lock"), Mutex::_no_safepoint_check_flag); thread->print_thread_state_on(tty); // If the lock above succeeds, try to safepoint to test the NSV implied with this nosafepoint lock. ThreadBlockInVM tbivm(thread); thread->print_thread_state_on(tty); } + #endif // ASSERT diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 094f16a4262b..26c8fb8cd72e 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 07764c45a7a5..cc11b0f6ff5f 100644 --- a/test/hotspot/gtest/threadHelper.inline.hpp +++ b/test/hotspot/gtest/threadHelper.inline.hpp @@ -169,7 +169,7 @@ class TestThreadGroup { } } ~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 7f2b0eedaa45..bd5c80093d42 100644 --- a/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp +++ b/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp @@ -42,7 +42,7 @@ class SimpleFakeBitmap { } ~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 8094e93b9442..163b11c213e0 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 bdba49b48c09..3c3558f00187 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 acdd6a315e58..a84d5ecef922 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 7eca5f54831b..bb306935f45d 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -851,6 +851,46 @@ struct ArrayAllocator { 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 0a2177b8edb9..3ebe405a046f 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 a6112169f8dc..ce22258d04a8 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 7c4846a9fb24..c6bea25d275a 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 e4f1774e6e06..f9a4d5ec2a97 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 1a831a0dde37..b28670c98397 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 d8779a873cd8..a30d6dfecff6 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 8514ffce11cf..351ef2a540c5 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 b4f9efff8304..3a55aceb3da8 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -79,7 +79,7 @@ compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all compiler/interpreter/Test6833129.java 8335266 generic-i586 compiler/intrinsics/TestReturnOopSetForJFRWriteCheckpoint.java 8286300 linux-s390x -compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 +compiler/c2/aarch64/TestStaticCallStub.java 8359963 generic-aarch64 compiler/unsafe/AlignmentGapAccess.java 8373487 generic-all @@ -95,7 +95,12 @@ 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/oom/TestThreadFailure.java 8382637 generic-all 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 +195,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/c2/irTests/TestFloat16ScalarOperations.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java index 445fef5e55a5..8f2bbe8a8a7c 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 void testSqrtConstantFolding() { @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 void testFMAConstantFolding() { @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/debug/TestStressBailout.java b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java index 68610576a390..f79cb679c413 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 @@ * @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/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java index fa81fa93f115..89dfae5c4da4 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.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 @@ -37,6 +37,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:TieredStopAtLevel=3 * TestAccessErrorInCatch + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+GenerateOopMapALot TestAccessErrorInCatch */ import java.lang.invoke.MethodHandle; diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java b/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java index 34583b8fea98..06057a34b615 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java @@ -64,6 +64,8 @@ static class OuterWithVolatileField { 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 000000000000..071c959477e4 --- /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 000000000000..0a42e2300074 --- /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:-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:-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/loopopts/TestLoopPeelingDisabled.java b/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java index e7bbe24d1def..f8ee2084f3ea 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java @@ -51,11 +51,14 @@ public static void main(String[] args) { // 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 2678aab9c40e..8179c33557c5 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 97a55ae20749..599e95bd6aba 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 @@ private static long longAddSimple() { @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 @@ private static long longAddSimple() { @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 @@ private static long longMaxSimple() { @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 @@ private static long longAndDotProduct() { @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 @@ private static long longOrDotProduct() { @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 @@ private static long longXorDotProduct() { @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 @@ private static long longAddDotProduct() { @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 @@ private static long longMulDotProduct() { @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 @@ private static long longMinDotProduct() { @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 @@ private static long longMaxDotProduct() { @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 @@ private static long longAndBig() { @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 @@ private static long longOrBig() { @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 @@ private static long longXorBig() { @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 @@ private static long longAddBig() { @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 @@ private static long longAddBig() { // 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 @@ private static long longMulBig() { @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 @@ private static long longMinBig() { @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 @@ private static long longMaxBig() { @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 @@ private static float floatAddSimple() { @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 @@ private static float floatMaxSimple() { @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 @@ private static float floatAddDotProduct() { @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 @@ private static float floatMaxDotProduct() { @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 @@ private static float floatAddBig() { @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 @@ private static float floatMaxBig() { @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 @@ private static double doubleAddSimple() { @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 @@ private static double doubleMaxSimple() { @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 @@ private static double doubleAddDotProduct() { @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 @@ private static double doubleMaxDotProduct() { @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 @@ private static double doubleAddBig() { @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 000000000000..f6a0f3086f76 --- /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 000000000000..ac07bc316d33 --- /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 13eafd8dc26e..e9bf906a1be9 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java @@ -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 @@ static void runMulReduce64() { @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,7 +93,7 @@ static void runMulReduce128() { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=32"}) static byte testMulReduce256() { return ByteVector.fromArray(ByteVector.SPECIES_256, input, 0) @@ -111,7 +111,7 @@ static void runMulReduce256() { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx512f", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx512f", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=64"}) static byte testMulReduce512() { return ByteVector.fromArray(ByteVector.SPECIES_512, input, 0) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java index be3ec3228925..532f0d22927c 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java @@ -640,7 +640,7 @@ public void runShortMaxIdeal() { @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 void runIntMaskedMinIdealSameMask() { @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 void runIntMaskedMaxIdealSameMask() { @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 void runIntMaskedMaxIdealFlippedInputs() { @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 void runIntMaskedMinIdealFlippedInputs() { @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 void runIntMaskedMinIdealDiffMaskMinMax() { @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 void runIntMaskedMinIdealDiffMaskMinMaxSwapped() { @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 void runIntMaskedMinIdealDiffMaskOuter() { @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 void runIntMaskedMinIdealAllDiffMask() { @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 void runByteMaskedMinIdealSameMask() { @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 void runByteMaskedMaxIdealSameMask() { @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 void runByteMaskedMaxIdealFlippedInputs() { @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 void runByteMaskedMinIdealFlippedInputs() { @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 void runByteMaskedMinIdealDiffMaskMinMax() { @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 void runByteMaskedMinIdealDiffMaskMinMaxSwapped() { @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 void runByteMaskedMinIdealDiffMaskOuter() { @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 void runByteMaskedMinIdealAllDiffMask() { @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 void runShortMaskedMinIdealSameMask() { @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 void runShortMaskedMaxIdealSameMask() { @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 void runShortMaskedMaxIdealFlippedInputs() { @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 void runShortMaskedMinIdealFlippedInputs() { @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 void runShortMaskedMinIdealDiffMaskMinMax() { @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 void runShortMaskedMinIdealDiffMaskMinMaxSwapped() { @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 void runShortMaskedMinIdealDiffMaskOuter() { @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 void runShortMaskedMinIdealAllDiffMask() { @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 void runLongMaskedMinIdealSameMask() { @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 void runLongMaskedMaxIdealSameMask() { @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 void runLongMaskedMaxIdealFlippedInputs() { @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 void runLongMaskedMinIdealFlippedInputs() { @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 void runLongMaskedMinIdealDiffMaskMinMax() { @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 void runLongMaskedMinIdealDiffMaskMinMaxSwapped() { @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 void runLongMaskedMinIdealDiffMaskOuter() { @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 void runLongMaskedMinIdealAllDiffMask() { @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 void runFloatMaskedMinIdealSameMask() { @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 void runFloatMaskedMaxIdealSameMask() { @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 void runFloatMaskedMaxIdealFlippedInputs() { @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 void runFloatMaskedMinIdealFlippedInputs() { @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 void runFloatMaskedMinIdealDiffMaskMinMax() { @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 void runFloatMaskedMinIdealDiffMaskMinMaxSwapped() { @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 void runFloatMaskedMinIdealDiffMaskOuter() { @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 void runFloatMaskedMinIdealAllDiffMask() { @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 void runDoubleMaskedMinIdealSameMask() { @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 void runDoubleMaskedMaxIdealSameMask() { @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 void runDoubleMaskedMaxIdealFlippedInputs() { @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 void runDoubleMaskedMinIdealFlippedInputs() { @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 void runDoubleMaskedMinIdealDiffMaskMinMax() { @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 void runDoubleMaskedMinIdealDiffMaskMinMaxSwapped() { @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 void runDoubleMaskedMinIdealDiffMaskOuter() { @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 c019f1163738..527041b58a6c 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java @@ -73,7 +73,7 @@ private static void verifyResult(int vlen) { 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 static void testVectorMaskStoreIdentityByte() { 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 static void testVectorMaskStoreIdentityByte256() { 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 static void testVectorMaskStoreIdentityShort() { 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 static void testVectorMaskStoreIdentityShort256() { 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 static void testVectorMaskStoreIdentityInt() { 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 static void testVectorMaskStoreIdentityInt256() { 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 static void testVectorMaskStoreIdentityLong() { 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 static void testVectorMaskStoreIdentityLong256() { 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 static void testVectorMaskStoreIdentityFloat() { 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 static void testVectorMaskStoreIdentityFloat256() { 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 static void testVectorMaskStoreIdentityDouble() { 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 static void main(String[] args) { .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 929a70f304aa..00a556cff8f5 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 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 void checkResultAdd() { @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 void checkResultSub() { @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 void checkResultMul() { @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 void checkResultDiv() { @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 void checkResultMin() { @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 void checkResultMax() { @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 void checkResultSqrt() { @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 void checkResultFma() { @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 void checkResultFmaScalarMixedConstants() { @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 void checkResultFmaMixedConstants() { @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 void checkResultFmaAllConstants() { @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/systemd/SystemdContainerDetectionTest.java b/test/hotspot/jtreg/containers/systemd/SystemdContainerDetectionTest.java new file mode 100644 index 000000000000..266e9a00309d --- /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 758747d451a1..000000000000 --- 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/shenandoah/TestLargeArrayInit.java b/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInit.java new file mode 100644 index 000000000000..9ce254ff845d --- /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 000000000000..34f3b70197a5 --- /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/TestSmallArrayInit.java b/test/hotspot/jtreg/gc/shenandoah/TestSmallArrayInit.java new file mode 100644 index 000000000000..3c15a140d186 --- /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 1ae3b690b0d4..e5c3acaccac6 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 void handleNotification(Notification n, Object o) { ((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 void handleNotification(Notification n, Object o) { 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 void handleNotification(Notification n, Object o) { } { - 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/TestSelectiveBarrierFlags.java b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java index fe29a38c422c..da66bb8bbe09 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java @@ -52,8 +52,7 @@ public static void main(String[] args) throws Exception { new String[] { "ShenandoahLoadRefBarrier" }, new String[] { "ShenandoahSATBBarrier" }, new String[] { "ShenandoahCASBarrier" }, - new String[] { "ShenandoahCloneBarrier" }, - new String[] { "ShenandoahStackWatermarkBarrier" } + new String[] { "ShenandoahCloneBarrier" } }; int size = 1; diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java index f461bb4ae5c0..b5c30f372028 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java @@ -41,8 +41,7 @@ public static void main(String[] args) throws Exception { "ShenandoahLoadRefBarrier", "ShenandoahSATBBarrier", "ShenandoahCASBarrier", - "ShenandoahCloneBarrier", - "ShenandoahStackWatermarkBarrier", + "ShenandoahCloneBarrier" }; String[] generational = { diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java index 348aa5367e97..1bc382dfbb07 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java @@ -41,8 +41,7 @@ public static void main(String[] args) throws Exception { "ShenandoahLoadRefBarrier", "ShenandoahSATBBarrier", "ShenandoahCASBarrier", - "ShenandoahCloneBarrier", - "ShenandoahStackWatermarkBarrier", + "ShenandoahCloneBarrier" }; String[] generational = { "ShenandoahCardBarrier" }; String[] all = { @@ -50,7 +49,6 @@ public static void main(String[] args) throws Exception { "ShenandoahSATBBarrier", "ShenandoahCASBarrier", "ShenandoahCloneBarrier", - "ShenandoahStackWatermarkBarrier", "ShenandoahCardBarrier" }; diff --git a/test/hotspot/jtreg/runtime/8359166/Test.java b/test/hotspot/jtreg/runtime/8359166/Test.java new file mode 100644 index 000000000000..509a06a3de14 --- /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/cds/appcds/aotCache/AOTCacheConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java new file mode 100644 index 000000000000..a48051bb6725 --- /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 000000000000..dea3171b08d7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdOnTrainingProcess.java @@ -0,0 +1,90 @@ +/* + * 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 jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; +import java.io.IOException; + +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"); + 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/interpreter/TraceBytecodesSignatures.java b/test/hotspot/jtreg/runtime/interpreter/TraceBytecodesSignatures.java new file mode 100644 index 000000000000..a7881582d8c3 --- /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 157c1713ec28..ab459f31931b 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 void run(CommandExecutor executor) { 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 void run(CommandExecutor executor) { } 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 void run(CommandExecutor executor) { 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"); - } - 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"); + + // 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); } - } 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 void run(CommandExecutor executor) { 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/serviceability/sa/ClhsdbPstack.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java index 51738be35546..6921a7ec0ca3 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java @@ -54,6 +54,10 @@ public class ClhsdbPstack { public static void main(String[] args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + boolean withCore = Boolean.parseBoolean(args[0]); System.out.println("Starting ClhsdbPstack test: withCore==" + withCore); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java index e3808aa67062..a5750edf360f 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java @@ -33,6 +33,8 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; + /** * @test * @key randomness @@ -174,6 +176,10 @@ private static void runJstackMixedInLoop(LingeredApp app) throws Exception { } public static void main(String... args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp app = null; diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index a3880bc9f0e7..70a9e67e4060 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2025, NTT DATA + * Copyright (c) 2025, 2026, NTT DATA * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,14 @@ import java.util.List; import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; + /** * @test id=xcomp * @bug 8370176 @@ -111,6 +114,10 @@ private static void runJstack(LingeredApp app) throws Exception { } public static void main(String... args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp app = null; diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java index f6580d71e057..e0774917f807 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java @@ -22,6 +22,7 @@ */ import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; @@ -43,6 +44,10 @@ public class TestJhsdbJstackPrintVMLocks { final static int MAX_ATTEMPTS = 5; public static void main(String[] args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp theApp = null; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java new file mode 100644 index 000000000000..840e8def8bc4 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java @@ -0,0 +1,106 @@ +/* + * 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 8074292 + * @summary Reproduce the bb->is_reachable() assert with GetSetLocals call after async exception. + * @library /vmTestbase + * /test/lib + * @compile -g kill003a.java + * @run driver + * nsk.jdb.kill.kill003.kill003 + * -arch=${os.family}-${os.simpleArch} + * -waittime=5 + * -verbose + * -debugee.vmkind=java + * -transport.address=dynamic + * -jdb=${test.jdk}/bin/jdb + * -java.options="${test.vm.opts} ${test.java.opts}" + * -workdir=. + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + */ + +package nsk.jdb.kill.kill003; + +import nsk.share.*; +import nsk.share.jdb.*; + +import java.io.*; +import java.util.*; + +public class kill003 extends JdbTest { + + public static void main (String argv[]) { + debuggeeClass = DEBUGGEE_CLASS; + firstBreak = FIRST_BREAK; + new kill003().runTest(argv); + } + + static final String PACKAGE_NAME = "nsk.jdb.kill.kill003"; + static final String TEST_CLASS = PACKAGE_NAME + ".kill003"; + static final String DEBUGGEE_CLASS = TEST_CLASS + "a"; + static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main"; + static final String MYTHREAD = "MyThread"; + static final String DEBUGGEE_THREAD = PACKAGE_NAME + "." + MYTHREAD; + static final String DEBUGGEE_EXCEPTION = DEBUGGEE_CLASS + ".exception"; + + protected void runCases() { + String[] reply; + String[] threads; + + // At this point we are at the breakpoint triggered by the firstBreak in main + // after creating all the threads. Get the list of debuggee threads. + threads = jdb.getThreadIdsByName("main"); + + // Stopped at kill.main, so step into synchronized block + reply = jdb.receiveReplyFor(JdbCommand.next); + + if (threads.length != 1) { + log.complain("jdb should report " + 1 + " instance of " + DEBUGGEE_THREAD); + log.complain("Found: " + threads.length); + success = false; + } + + // Execution is at a bytecode that is not expected to handle an async exception. Throw one here + // to make sure it gets handled without crashing. The exception will be delivered at the next + // bytecode that can handle the async exception. + reply = jdb.receiveReplyForWithMessageWait(JdbCommand.kill + threads[0] + " " + DEBUGGEE_EXCEPTION, + "killed"); + + // Continue the debuggee - the async exception will be delivered to the debuggee. + reply = jdb.receiveReplyFor(JdbCommand.cont); + + // Ask the debuggee for its local variables at the bytecode where the async exception was delivered, which + // should be reachable. + reply = jdb.receiveReplyForWithMessageWait(JdbCommand.locals, "Local variables"); + + if (jdb.terminated()) { + throw new Failure("Debuggee exited"); + } + + // The lack of exception handler in the debuggee should cause it to exit when continued. + jdb.contToExit(1); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java new file mode 100644 index 000000000000..1e72e02a5600 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package nsk.jdb.kill.kill003; + +import nsk.share.jdb.*; + +/* This is debuggee application */ +public class kill003a { + static NullPointerException exception = new NullPointerException(); + + public static void main(String args[]) { + synchronized (args) { + } + System.out.println("done"); + System.exit(JdbTest.JCK_STATUS_BASE); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp index a2e9716a5138..4b929fd4d03d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, 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 @@ -39,6 +39,7 @@ static jvmtiEventCallbacks callbacks; static jint result = PASSED; static jboolean printdump = JNI_FALSE; static jmethodID mid; +static jclass testThreadClass = nullptr; void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jmethodID method, jlocation location) { @@ -166,6 +167,8 @@ Java_nsk_jvmti_PopFrame_popframe007_getReady(JNIEnv *env, return; } + testThreadClass = (jclass)env->NewGlobalRef(clazz); + err = jvmti->SetBreakpoint(mid, 0); if (err != JVMTI_ERROR_NONE) { printf("(SetBreakpoint) unexpected error: %s (%d)\n", @@ -191,7 +194,7 @@ Java_nsk_jvmti_PopFrame_popframe007_getRes(JNIEnv *env, jclass cls) { JNIEXPORT void JNICALL Java_nsk_jvmti_PopFrame_popframe007_B(JNIEnv *env, jclass cls) { if (mid != nullptr) { - env->CallStaticVoidMethod(cls, mid); + env->CallStaticVoidMethod(testThreadClass, mid); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp index cda8481533db..f7ad0b65ff30 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, 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 @@ -113,6 +113,12 @@ ClassFileLoadHook ( loader, method_id, class_name_string)) != nullptr)) return; + if (jni->ExceptionCheck()) { + jni->ExceptionDescribe(); + jni->ExceptionClear(); + return; + } + if (!NSK_VERIFY((method_id = jni->GetStaticMethodID( callback_class, "callback", "(Ljava/lang/String;I)V")) != nullptr)) return; @@ -120,7 +126,7 @@ ClassFileLoadHook ( if (!NSK_VERIFY((class_name_string = jni->NewStringUTF(name)) != nullptr)) return; - jni->CallStaticObjectMethod(callback_class, method_id, class_name_string, agent_id); + NSK_JNI_VERIFY_VOID(jni, jni->CallStaticVoidMethod(callback_class, method_id, class_name_string, agent_id)); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp index 7f622c24f75c..7f82caa72599 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp @@ -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 @@ -31,6 +31,20 @@ extern "C" { static volatile int internalError = 0; +/* + * Check for pending JNI exceptions after a JNI call. + * If an exception is found, describe it, clear it, and return failure. + */ +static int nsk_aod_checkJNIException(JNIEnv* jni) { + if (jni->ExceptionCheck()) { + jni->ExceptionDescribe(); + jni->ExceptionClear(); + NSK_COMPLAIN0("Unexpected exception after JNI call\n"); + return NSK_FALSE; + } + return NSK_TRUE; +} + /* * This function can be used to inform AOD framework that some non critical for test logic * error happened inside shared function (e.g. JVMTI Deallocate failed). @@ -227,6 +241,10 @@ int nsk_aod_agentLoaded(JNIEnv* jni, const char* agentName) { jni->CallStaticVoidMethod(targetAppClass, agentLoadedMethod, agentNameString); + if (!nsk_aod_checkJNIException(jni)) { + return NSK_FALSE; + } + return NSK_TRUE; } @@ -263,6 +281,10 @@ int nsk_aod_agentFinished(JNIEnv* jni, const char* agentName, int success) { jni->CallStaticVoidMethod(targetAppClass, agentFinishedMethod, agentNameString, success ? JNI_TRUE : JNI_FALSE); + if (!nsk_aod_checkJNIException(jni)) { + return NSK_FALSE; + } + return NSK_TRUE; } diff --git a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java index b9218480788b..7ca852f2726d 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 8f7380a43f8c..a30f1ad30ed5 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 c98bf63b25f8..1f99d0f6859d 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 700099656e89..fc3f22261002 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 52f187086de1..8dd65f257f88 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 44bad411f261..5b104f08b16a 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 1a831a0dde37..b28670c98397 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 e9019b6014e3..e96ad2d9b99b 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 522b77cb502f..533ad5d613c7 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 a669f3e3abf5..ae3d8c33e96a 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 f1bd91d86aab..4299754d43e0 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -151,6 +151,7 @@ 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 @@ -386,36 +387,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 @@ -748,8 +745,6 @@ jdk/jfr/jvm/TestWaste.java 8371630 generic- # jdk_foreign -java/foreign/TestBufferStackStress.java 8350455 macosx-all - ############################################################################ # Client manual tests @@ -804,10 +799,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 b8f517d04487..d1f45e254e64 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 @@ void breakpointAtMethod(ReferenceType ref, String methodName) } } + private static boolean isHiddenClass(String className) { + return className.contains("/"); + } + protected void runTests() throws Exception { BreakpointEvent bpe = startToMain("ClassesByName2Targ"); @@ -160,6 +164,13 @@ is slow (eg, -Xcomp -server) - we don't want to 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 000000000000..17c7d34fa474 --- /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 000000000000..4db4637f4320 --- /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 000000000000..ac29b270c81f --- /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 000000000000..7757eb61b087 --- /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 000000000000..73c131c1105a --- /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/foreign/StdLibTest.java b/test/jdk/java/foreign/StdLibTest.java index f1e35b53a398..aa9102cc1683 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.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 @@ void test_rand() throws Throwable { 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 @@ void test_printf(List args) throws Throwable { 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 @@ void testSystemLibraryBadLookupName() { 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 @@ static class StdLibHelper { 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 @@ Tm gmtime(long arg) throws Throwable { } } - 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 @@ int[] qsort(int[] arr) throws Throwable { 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 @@ int[] qsort(int[] arr) throws Throwable { 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 @@ private MethodHandle specializedPrintf(List args) { 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 @@ private MethodHandle specializedPrintf(List args) { /*** 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() { - return perms(0, new String[] { "a", "b", "c" }).stream() - .map(l -> new Object[] { String.join("", l) }) - .toArray(Object[][]::new); + static Stream strings() { + return strings0() + .map(Arguments::of); } - @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; + static Stream stringPairs() { + return strings0() + .flatMap(s -> strings0() + .map(s2 -> Arguments.of(s, s2))); } - @DataProvider - public static Object[][] instants() { + static Stream strings0() { + return perms(0, new String[] { "a", "b", "c" }).stream() + .map(l -> String.join("", l)); + } + + 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 static Object[][] printfArgs() { 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 0ec46311a6f1..a0b7348331ce 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 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 402ce6bbe947..cf02d5ae6083 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 cf335e4ff886..963063378a30 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 void testOffset(SegmentSlice s1, SegmentSlice s2) { 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 void testOffset(SegmentSlice s1, SegmentSlice s2) { } } - static class SegmentSlice { + final static class SegmentSlice { enum Kind { NATIVE(i -> Arena.ofAuto().allocate(i, 1)), @@ -94,7 +96,7 @@ MemorySegment makeSegment(int elems) { 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 @@ long offset(SegmentSlice that) { } } - @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 @@ static Object[][] slices() { } } } - 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 111e3cf8ab2c..4201fff3bb77 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 @@ void lastIndex() { 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 @@ static Stream unsupportedOperations() { ); } + 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/net/httpclient/HeadTest.java b/test/jdk/java/net/httpclient/HeadTest.java index c0bef2405209..5694e4f60166 100644 --- a/test/jdk/java/net/httpclient/HeadTest.java +++ b/test/jdk/java/net/httpclient/HeadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -22,14 +22,25 @@ */ /* - * @test - * @bug 8203433 8276559 + * @test id=withCertificateCompression + * @bug 8203433 8276559 8372526 * @summary Tests Client handles HEAD and 304 responses correctly. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * @run junit/othervm -Djdk.httpclient.HttpClient.log=trace,headers,requests ${test.main.class} */ +/* + * @test id=withoutCertificateCompression + * @bug 8203433 8276559 8372526 + * @summary Tests Client handles HEAD and 304 responses correctly. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.test.lib.net.SimpleSSLContext + * @run junit/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * -Djdk.tls.server.disableExtensions=compress_certificate + * -Djdk.httpclient.HttpClient.log=trace,headers,requests HeadTest + */ + import jdk.test.lib.net.SimpleSSLContext; import javax.net.ssl.SSLContext; diff --git a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java index 4544c85c5e85..dd1e2495382a 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java @@ -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 @@ -112,8 +112,8 @@ public static void main(String[] args) throws Exception { builder = test1("headers", builder, builder::headers, (String[]) null, NullPointerException.class); - builder = test1("headers", builder, builder::headers, new String[0], - IllegalArgumentException.class); + builder = test1("headers", builder, builder::headers, new String[0] + /* no expected exceptions */); builder = test1("headers", builder, builder::headers, (String[]) new String[] {null, "bar"}, diff --git a/test/jdk/java/net/httpclient/LargeHandshakeTest.java b/test/jdk/java/net/httpclient/LargeHandshakeTest.java index 59cdad27cbc8..ec4cd8be4aa9 100644 --- a/test/jdk/java/net/httpclient/LargeHandshakeTest.java +++ b/test/jdk/java/net/httpclient/LargeHandshakeTest.java @@ -66,9 +66,9 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; import static java.net.http.HttpOption.H3_DISCOVERY; -/** - * @test - * @bug 8231449 +/* + * @test id=withCertificateCompression + * @bug 8231449 8372526 * @summary This test verifies that the HttpClient works correctly when the server * sends a large certificate. This test will not pass without * the fix for JDK-8231449. To regenerate the certificate, modify the @@ -91,6 +91,35 @@ * ${test.main.class} * */ + +/* + * @test id=withoutCertificateCompression + * @bug 8231449 8372526 + * @summary This test verifies that the HttpClient works correctly when the server + * sends a large certificate. This test will not pass without + * the fix for JDK-8231449. To regenerate the certificate, modify the + * COMMAND constant as you need, possibly changing the start date + * and validity of the certificate in the command, then run the test. + * The test will run with the old certificate, but will print the new command. + * Copy paste the new command printed by this test into a terminal. + * Then modify the at run line to pass the file generated by that command + * as first argument, and copy paste the new values of the COMMAND and + * BASE64_CERT constant printed by the test into the test. + * Then restore the original at run line and test again. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext + * DigestEchoServer + * jdk.httpclient.test.lib.common.TestServerConfigurator + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * -Djdk.tls.server.disableExtensions=compress_certificate + * -Dtest.requiresHost=true + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=true + * -Djdk.tls.maxHandshakeMessageSize=131072 + * LargeHandshakeTest + * + */ + public class LargeHandshakeTest implements HttpServerAdapters { // Use this command to regenerate the keystore file whose content is diff --git a/test/jdk/java/net/httpclient/RequestBuilderTest.java b/test/jdk/java/net/httpclient/RequestBuilderTest.java index 6ba00fcd10fa..9285bb55bb8e 100644 --- a/test/jdk/java/net/httpclient/RequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/RequestBuilderTest.java @@ -202,11 +202,10 @@ public void testMethod() { public void testHeaders() { HttpRequest.Builder builder = newBuilder(uri); - String[] empty = new String[0]; - assertThrows(IAE, () -> builder.headers(empty).build()); assertThrows(IAE, () -> builder.headers("1").build()); assertThrows(IAE, () -> builder.headers("1", "2", "3").build()); assertThrows(IAE, () -> builder.headers("1", "2", "3", "4", "5").build()); + assertEquals(0, builder.headers(new String[0]).build().headers().map().size()); assertEquals(0, builder.build().headers().map().size()); List requests = List.of( diff --git a/test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.java b/test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.java new file mode 100644 index 000000000000..9df68cf0ca0b --- /dev/null +++ b/test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.java @@ -0,0 +1,107 @@ +/* + * 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.awt.FlowLayout; +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; + +/* + * @test + * @key headful + * @bug 8377936 + * @summary manual test for VoiceOver reading button names and states + * @requires os.family == "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual VoiceOverNamesAndStates + */ + +public class VoiceOverNamesAndStates { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + INSTRUCTIONS: + + Part A: + 1. Open VoiceOver + 2. Move the VoiceOver cursor to the leftmost button. + 3. Press CTRL + ALT + RIGHT to move to the rightmost button. + + Expected behavior: VoiceOver should announce rightmost button. + (It should NOT announce the leftmost button.) + + Part B (Regression for 8061359, 8348936, 8309733): + 1. Open VoiceOver + 2. Move the VoiceOver cursor to the leftmost button. + 3. Press SPACE to trigger Swing's default KeyListeners. + 4. Repeat step 3 to untoggle button. + 5. Press CTRL + ALT + SPACE to trigger VO's listeners. + 6. Repeat step 5 to untoggle button + + Expected behavior: VoiceOver should announce the change in the + button state in steps 3-6. (When you use VoiceOver to toggle + the button you should hear a small chirp as the button + toggles.) + + Part C (Regression for 8345728, 8283400): + 1. Turn on Screen Magnifier + (See System Settings -> Accessibility -> Hover Text) + 2. Press CMD key and hover mouse over leftmost button + 3. Click the button + 4. Release the CMD key + + Expected behavior: both the button and the "hover text" window + repaint to show a selected button. + + 5. Repeat steps 2-4 to untoggle the button + + Expected behavior: both the button and the "hover text" window + repaint to show a deselected button. + + """; + + PassFailJFrame.builder() + .title("VoiceOverNamesAndStates Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(VoiceOverNamesAndStates::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame f = new JFrame(); + + f.getContentPane().setLayout(new FlowLayout()); + + AbstractButton button1 = new JCheckBox("chess"); + AbstractButton button2 = new JButton("backgammon"); + + f.getContentPane().add(button1); + f.getContentPane().add(button2); + f.pack(); + f.setVisible(true); + return f; + } +} diff --git a/test/jdk/javax/accessibility/8380849/AccessibleActionAsSeparateClassTest.java b/test/jdk/javax/accessibility/8380849/AccessibleActionAsSeparateClassTest.java new file mode 100644 index 000000000000..cd3bf6d46c8d --- /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/net/ssl/SSLSession/TestEnabledProtocols.java b/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java index 4e56a9a655b3..070991586f32 100644 --- a/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java +++ b/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, 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 @@ -40,10 +40,10 @@ import java.io.IOException; import java.io.InputStream; -import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.security.Security; import java.util.Arrays; @@ -88,11 +88,9 @@ protected void runServerApplication(SSLSocket socket) throws Exception { // log it for debugging System.out.println("Server SSLHandshakeException:"); se.printStackTrace(System.out); - } catch (InterruptedIOException ioe) { - // must have been interrupted, no harm - } catch (SSLException | SocketException se) { + } catch (SocketTimeoutException | SSLException | SocketException se) { // The client side may have closed the socket. - System.out.println("Server SSLException:"); + System.out.println("Server exception:"); se.printStackTrace(System.out); } catch (Exception e) { System.out.println("Server exception:"); diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java index 34cccb5356c6..0a825d6cc7d3 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.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 @@ -430,10 +430,10 @@ public static boolean isEmpty(String str) { public static String expectedNegoAppProtocol(String[] serverAppProtocols, String[] clientAppProtocols) { if (serverAppProtocols != null && clientAppProtocols != null) { - for(String clientAppProtocol : clientAppProtocols) { - for(String serverAppProtocol : serverAppProtocols) { - if (clientAppProtocol.equals(serverAppProtocol)) { - return clientAppProtocol; + for(String serverAppProtocol : serverAppProtocols) { + for(String clientAppProtocol : clientAppProtocols) { + if (serverAppProtocol.equals(clientAppProtocol)) { + return serverAppProtocol; } } } diff --git a/test/jdk/javax/net/ssl/compatibility/AlpnTest.java b/test/jdk/javax/net/ssl/compatibility/AlpnTest.java index 71a60fe54356..86b75f4d2c31 100644 --- a/test/jdk/javax/net/ssl/compatibility/AlpnTest.java +++ b/test/jdk/javax/net/ssl/compatibility/AlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -36,6 +36,8 @@ * @run main/manual AlpnTest false */ +import jtreg.SkippedException; + import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -98,6 +100,19 @@ protected List> getTestCases() { clientCase.setCipherSuites(cipherSuite); clientCase.setAppProtocols("h2"); + testCases.add( + new TestCase(serverCase, clientCase)); + + serverCase = ExtUseCase.newInstance(); + serverCase.setCertTuple(certTuple); + serverCase.setAppProtocols("http/1.1", "h2"); + + clientCase = ExtUseCase.newInstance(); + clientCase.setCertTuple(certTuple); + clientCase.setProtocols(protocol); + clientCase.setCipherSuites(cipherSuite); + clientCase.setAppProtocols("h2", "http/1.1"); + testCases.add( new TestCase(serverCase, clientCase)); } @@ -171,6 +186,10 @@ public static void main(String[] args) throws Exception { Boolean defaultJdkAsServer = Boolean.valueOf(args[0]); Set jdkInfos = Utils.jdkInfoList(); + if (jdkInfos.isEmpty()) { + throw new SkippedException("No JDKs to test"); + } + for (JdkInfo jdkInfo : jdkInfos) { AlpnTest test = new AlpnTest( defaultJdkAsServer ? JdkInfo.DEFAULT : jdkInfo, diff --git a/test/jdk/javax/swing/JDesktopPane/TestDesktopManagerNPE.java b/test/jdk/javax/swing/JDesktopPane/TestDesktopManagerNPE.java index 4a5d6329b058..b77fab3bd272 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.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/incubator/vector/VectorMathLibraryLocaleTest.java b/test/jdk/jdk/incubator/vector/VectorMathLibraryLocaleTest.java new file mode 100644 index 000000000000..c093df397e54 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/VectorMathLibraryLocaleTest.java @@ -0,0 +1,53 @@ +/* + * 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 8382267 + * @summary VectorMathLibrary symbol names must not use locale-sensitive formatting + * @modules jdk.incubator.vector + * @run main/othervm -ea -Duser.language=ar -Duser.country=SA VectorMathLibraryLocaleTest + */ + +import java.util.Locale; + +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.VectorOperators; +import jdk.incubator.vector.VectorSpecies; + +public class VectorMathLibraryLocaleTest { + public static void main(String[] args) { + assert !String.format("%d", 16).equals("16") : "expected non-ASCII digits for locale " + Locale.getDefault(); + + VectorSpecies species = FloatVector.SPECIES_PREFERRED; + FloatVector v = FloatVector.broadcast(species, 1.0f); + + // Without the fix, this throws InternalError due to locale-mangled symbol name. + // The assertion below is just a sanity check on the result. + FloatVector result = v.lanewise(VectorOperators.EXP); + float expected = (float) Math.E; + for (int i = 0; i < species.length(); i++) { + assert result.lane(i) == expected : "lane " + i + ": expected " + expected + ", got " + result.lane(i); + } + } +} diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java new file mode 100644 index 000000000000..8bbadc6db290 --- /dev/null +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package jdk.jfr.api.consumer.streaming; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.CountDownLatch; + +import jdk.jfr.Event; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Test that it is possible to register new metadata in a new segment while retaining the string pool. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.consumer.streaming.TestMetadataReconstructionWithRetainedStringPool + */ +public class TestMetadataReconstructionWithRetainedStringPool { + /// Minimum string length required to trigger StringPool usage. + /// Mirrors `jdk.jfr.internal.StringPool.MIN_LIMIT`. + private static final int STRING_POOL_MIN_LIMIT = 16; + private static final int EXPECTED_EVENTS = 3; + + // Condition 1: String length > STRING_POOL_MIN_LIMIT triggers CONSTANT_POOL encoding. + private static final String TEXT = "a".repeat(STRING_POOL_MIN_LIMIT + 1);; + + static final class EventA extends Event { + String text = TEXT; + } + + static final class EventB extends Event { + String text = TEXT; + } + + public static void main(String... args) throws InterruptedException { + var aEventsPosted = new CountDownLatch(1); + var readyToPostEventB = new CountDownLatch(1); + var remaining = new CountDownLatch(EXPECTED_EVENTS); + + try (var rs = new RecordingStream()) { + rs.onEvent(e -> { + String textValue = e.getValue("text"); + if (textValue == null) { + throw new RuntimeException("e.getValue(\"text\") returned null"); + } + remaining.countDown(); + System.out.printf("Event #%d [%s]: text=%s%n", + EXPECTED_EVENTS - remaining.getCount(), + e.getEventType().getName(), + textValue); + }); + + rs.onFlush(() -> { + if (aEventsPosted.getCount() == 0) { + readyToPostEventB.countDown(); + } + }); + + rs.startAsync(); + + // Condition 2: Two distinct event types are required. + // First, load EventA as the initial event type and emit its first event. + // This first event looks into the StringPool pre-cache. Although the + // string length qualifies for pooling, because it isn't pre-cached, + // the first event encodes the string inline. + // The second event finds the string in the pre-cache and adds it to the + // pool. A constant pool ID to the pooled string is encoded in the event. + // + new EventA().commit(); + new EventA().commit(); + aEventsPosted.countDown(); + + // Condition 3: Wait for JFR flush. + // The default flush period is ~1 second. + readyToPostEventB.await(); + + // Load the second event type, EventB, AFTER the flush segment containing the two events of type EventA. + // A new metadata description will be constructed, and we verify that the StringPool added in the previous + // segment is still available for the EventB string pool reference to be resolved correctly. + new EventB().commit(); + remaining.await(); + } + } +} diff --git a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java index 12c9d6c40fa7..266eb73a6566 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.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 @@ -34,7 +34,7 @@ import jdk.test.whitebox.code.BlobType; /** - * @test TestCodeCacheFull + * @test id=Default * @requires vm.hasJFR * @requires vm.opt.UseCodeCacheFlushing == null | vm.opt.UseCodeCacheFlushing == true * @@ -50,6 +50,20 @@ * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeCacheFull + */ + +/** + * @test id=HotCode + * @requires vm.hasJFR + * @requires vm.opt.UseCodeCacheFlushing == null | vm.opt.UseCodeCacheFlushing == true + * @requires vm.compiler2.enabled + * + * @library /test/lib + * @modules jdk.jfr + * jdk.management.jfr + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M jdk.jfr.event.compiler.TestCodeCacheFull diff --git a/test/jdk/sun/security/krb5/RFC396xTest.java b/test/jdk/sun/security/krb5/RFC396xTest.java index e8f48d7c4887..fd011c7f1980 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 e03b4fe50986..04ee2960daa9 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 static void main(String[] args) throws Exception { 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 37a4e828469d..168a84722c7e 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -366,11 +366,12 @@ public void writeKtab(String tab, boolean append, String... names) 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 @@ private static EncryptionKey generateRandomKey(int eType) */ 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 @@ private char[] getPassword(PrincipalName p, boolean server) * @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 @@ protected byte[] getParams(PrincipalName p, int etype) { 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 @@ protected byte[] getParams(PrincipalName p, int etype) { } } + /** + * 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 000000000000..f972e20ee1e1 --- /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/ssl/CertificateCompression/BoundDecompressMemory.java b/test/jdk/sun/security/ssl/CertificateCompression/BoundDecompressMemory.java new file mode 100644 index 000000000000..92e771f2a4a8 --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/BoundDecompressMemory.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. + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertNotNull; +import static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; +import static jdk.test.lib.security.SecurityUtils.runAndGetLog; + +import java.util.Scanner; +import javax.net.ssl.SSLHandshakeException; + +/* + * @test + * @bug 8372526 + * @summary Bound the memory usage when decompressing CompressedCertificate. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm BoundDecompressMemory + */ + +public class BoundDecompressMemory extends CompressedCertMsgCache { + + private static final int MAX_HANDSHAKE_MESSAGE_SIZE = 4096; + + public static void main(String[] args) throws Exception { + System.setProperty("jdk.tls.maxHandshakeMessageSize", + Integer.toString(MAX_HANDSHAKE_MESSAGE_SIZE)); + + String log = runAndGetLog(() -> { + try { + // Use highly compressible subject name for server's certificate. + serverCertSubjectName = "O=Some-Org" + + "A".repeat(MAX_HANDSHAKE_MESSAGE_SIZE) + + ", L=Some-City, ST=Some-State, C=US"; + + setupCertificates(); + serverSslContext = getSSLContext(trustedCert, serverCert, + serverKeys.getPrivate(), "TLSv1.3"); + clientSslContext = getSSLContext(trustedCert, clientCert, + clientKeys.getPrivate(), "TLSv1.3"); + + runAndCheckException(() -> new BoundDecompressMemory().run(), + serverEx -> { + Throwable clientEx = serverEx.getSuppressed()[0]; + assertTrue( + clientEx instanceof SSLHandshakeException); + assertEquals("(bad_certificate) Improper " + + "certificate compression", + clientEx.getMessage()); + } + ); + } catch (Exception _) { + } + }); + + // Check for the specific decompression error message. + assertNotNull(new Scanner(log).findWithinHorizon("The size of the " + + "uncompressed certificate message " + + "exceeds maximum allowed size of " + + MAX_HANDSHAKE_MESSAGE_SIZE + + " bytes; compressed size: \\d+", 0)); + } +} diff --git a/test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java b/test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java new file mode 100644 index 000000000000..2708f1e6872e --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java @@ -0,0 +1,157 @@ +/* + * 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 static jdk.test.lib.Asserts.assertEquals; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/* + * @test + * @bug 8372526 + * @summary Add support for ZLIB TLS Certificate Compression. + * @library /javax/net/ssl/templates + * /test/lib + * + * @run main/othervm ClientCertCompressionExt + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * ClientCertCompressionExt + * + */ + +public class ClientCertCompressionExt extends SSLEngineTemplate { + + private static final int CLI_HELLO_MSG = 1; + private static final int COMP_CERT_EXT = 27; + // zlib(1), brotli(2), zstd(3) + private static final List DEFAULT_COMP_ALGS = List.of(1); + + ClientCertCompressionExt() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + new ClientCertCompressionExt().runTest( + !System.getProperty("jdk.tls.client.disableExtensions", "") + .contains("compress_certificate")); + } + + private void runTest(boolean shouldProduceExt) throws Exception { + // Produce client_hello + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); + + checkClientHello(shouldProduceExt); + } + + private void checkClientHello(boolean shouldProduceExt) throws Exception { + List compCertExt = getCompAlgsCliHello( + extractHandshakeMsg(cTOs, CLI_HELLO_MSG, false)); + + if (shouldProduceExt) { + assertEquals(DEFAULT_COMP_ALGS, compCertExt, + "Unexpected compress_certificate extension algorithms: " + + compCertExt); + } else { + assertEquals(compCertExt.size(), 0, + "compress_certificate extension present in ClientHello"); + } + } + + /** + * Parses the ClientHello message and extracts from it a list of + * compression algorithm values. It is assumed that the provided + * ByteBuffer has its position set at the first byte of the ClientHello + * message body (AFTER the handshake header) and contains the entire + * hello message. Upon successful completion of this method the ByteBuffer + * will have its position reset to the initial offset in the buffer. + * If an exception is thrown the position at the time of the exception + * will be preserved. + * + * @param data The ByteBuffer containing the ClientHello bytes. + * @return A List of the compression algorithm values. + */ + private List getCompAlgsCliHello(ByteBuffer data) { + Objects.requireNonNull(data); + data.mark(); + + // Skip over the protocol version and client random + data.position(data.position() + 34); + + // Jump past the session ID (if there is one) + int sessLen = Byte.toUnsignedInt(data.get()); + if (sessLen != 0) { + data.position(data.position() + sessLen); + } + + // Jump past the cipher suites + int csLen = Short.toUnsignedInt(data.getShort()); + if (csLen != 0) { + data.position(data.position() + csLen); + } + + // ...and the compression + int compLen = Byte.toUnsignedInt(data.get()); + if (compLen != 0) { + data.position(data.position() + compLen); + } + + List extSigAlgs = getCompAlgsFromExt(data); + + // We should be at the end of the ClientHello + data.reset(); + return extSigAlgs; + } + + /** + * Gets compression algorithms from the given TLS extension. + * The buffer should be positioned at the start of the extension. + */ + private List getCompAlgsFromExt(ByteBuffer data) { + + List extCompAlgs = new ArrayList<>(); + data.getShort(); // read length + + while (data.hasRemaining()) { + int extType = Short.toUnsignedInt(data.getShort()); + int extLen = Short.toUnsignedInt(data.getShort()); + + if (extType == COMP_CERT_EXT) { + int sigSchemeLen = data.get(); + + for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) { + Integer schemeName = Short.toUnsignedInt(data.getShort()); + extCompAlgs.add(schemeName); + } + } else { + // Not the extension we're looking for. Skip past the + // extension data + data.position(data.position() + extLen); + } + } + + return extCompAlgs; + } +} diff --git a/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java new file mode 100644 index 000000000000..265ba3a8fc97 --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java @@ -0,0 +1,151 @@ +/* + * 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 static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.security.SecurityUtils.countSubstringOccurrences; +import static jdk.test.lib.security.SecurityUtils.runAndGetLog; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; + +/* + * @test + * @bug 8372526 + * @summary Add support for ZLIB TLS Certificate Compression + * @library /javax/net/ssl/templates + * /test/lib + * + * @run main/othervm CompressedCertMsg + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate CompressedCertMsg + * @run main/othervm -Djdk.tls.server.disableExtensions=compress_certificate CompressedCertMsg + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * -Djdk.tls.server.disableExtensions=compress_certificate + * CompressedCertMsg + */ + +public class CompressedCertMsg extends SSLSocketTemplate { + + private static final String PRODUCED_COMP_CERT_MSG = + """ + Produced CompressedCertificate handshake message ( + "CompressedCertificate": { + "algorithm": "ZLIB", + """; + + private static final String CONSUMING_COMP_CERT_MSG = + """ + Consuming CompressedCertificate handshake message ( + "CompressedCertificate": { + "algorithm": "ZLIB", + """; + + private static final String IGNORE_EXT_MSG = + """ + Ignore unknown or unsupported extension ( + "compress_certificate (27)": { + """; + + private static final String CH_EXT = + """ + }, + "compress_certificate (27)": { + "compression algorithms": [ZLIB] + }, + """; + + private static final String CR_EXT = + """ + "CertificateRequest": { + "certificate_request_context": "", + "extensions": [ + "compress_certificate (27)": { + "compression algorithms": [ZLIB] + """; + + // Server sends CertificateRequest and gets a certificate + // from the client as well as the client from the server. + @Override + protected void configureServerSocket(SSLServerSocket sslServerSocket) { + SSLParameters sslParameters = sslServerSocket.getSSLParameters(); + sslParameters.setNeedClientAuth(true); + sslServerSocket.setSSLParameters(sslParameters); + } + + public static void main(String[] args) throws Exception { + boolean clientSideEnabled = !System.getProperty( + "jdk.tls.client.disableExtensions", "") + .contains("compress_certificate"); + boolean serverSideEnabled = !System.getProperty( + "jdk.tls.server.disableExtensions", "") + .contains("compress_certificate"); + + // Complete 1 handshake. + String log = runAndGetLog(() -> { + try { + new CompressedCertMsg().run(); + } catch (Exception _) { + } + }); + + // To make the test pass on Windows. + log = log.replace("\r\n", "\n"); + + if (clientSideEnabled && serverSideEnabled) { + // Make sure CompressedCertificate message is produced and consumed + // twice - by the server and by the client. + assertEquals(2, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(2, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + // Extensions are produced and consumed, so they appear in the + // log twice. + assertEquals(2, countSubstringOccurrences(log, CH_EXT)); + assertEquals(2, countSubstringOccurrences(log, CR_EXT)); + assertEquals(0, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } else if (clientSideEnabled) { + assertEquals(0, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + assertEquals(2, countSubstringOccurrences(log, CH_EXT)); + assertEquals(0, countSubstringOccurrences(log, CR_EXT)); + assertEquals(1, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } else if (serverSideEnabled) { + assertEquals(0, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, CH_EXT)); + assertEquals(2, countSubstringOccurrences(log, CR_EXT)); + assertEquals(1, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } else { + assertEquals(0, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, CH_EXT)); + assertEquals(0, countSubstringOccurrences(log, CR_EXT)); + assertEquals(0, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } + } +} diff --git a/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java new file mode 100644 index 000000000000..42e9701c6d0d --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java @@ -0,0 +1,197 @@ +/* + * 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 static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.security.SecurityUtils.countSubstringOccurrences; +import static jdk.test.lib.security.SecurityUtils.runAndGetLog; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import jdk.test.lib.security.CertificateBuilder; + +/* + * @test + * @bug 8372526 + * @summary Check CompressedCertificate message cache. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm CompressedCertMsgCache + */ + +public class CompressedCertMsgCache extends SSLSocketTemplate { + + protected static String clientCertSubjectName = + "CN=localhost, OU=SSL-Client, ST=Some-State, C=US"; + protected static String serverCertSubjectName = + "O=Some-Org, L=Some-City, ST=Some-State, C=US"; + + protected static X509Certificate trustedCert; + protected static X509Certificate serverCert; + protected static X509Certificate clientCert; + protected static KeyPair serverKeys; + protected static KeyPair clientKeys; + protected static SSLContext serverSslContext; + protected static SSLContext clientSslContext; + + public static void main(String[] args) throws Exception { + + // Complete 3 handshakes with the same SSLContext. + String log = runAndGetLog(() -> { + try { + setupCertificates(); + serverSslContext = getSSLContext(trustedCert, serverCert, + serverKeys.getPrivate(), "TLSv1.3"); + clientSslContext = getSSLContext(trustedCert, clientCert, + clientKeys.getPrivate(), "TLSv1.3"); + + new CompressedCertMsgCache().run(); + new CompressedCertMsgCache().run(); + new CompressedCertMsgCache().run(); + } catch (Exception _) { + } + }); + + // The same CompressedCertificate message must be cached only once. + assertEquals(1, countSubstringOccurrences(log, + "Caching CompressedCertificate message")); + + // Make sure CompressedCertificate message is produced 3 times. + assertEquals(3, countSubstringOccurrences(log, + "Produced CompressedCertificate handshake message")); + + // Make sure CompressedCertificate message is consumed 3 times. + assertEquals(3, countSubstringOccurrences(log, + "Consuming CompressedCertificate handshake message")); + } + + @Override + public SSLContext createServerSSLContext() throws Exception { + return serverSslContext; + } + + @Override + public SSLContext createClientSSLContext() throws Exception { + return clientSslContext; + } + + protected static SSLContext getSSLContext( + X509Certificate trustedCertificate, X509Certificate keyCertificate, + PrivateKey privateKey, String protocol) + throws Exception { + + // create a key store + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + // import the trusted cert + ks.setCertificateEntry("TLS Signer", trustedCertificate); + + // generate certificate chain + Certificate[] chain = new Certificate[2]; + chain[0] = keyCertificate; + chain[1] = trustedCertificate; + + // import the key entry. + final char[] passphrase = "passphrase".toCharArray(); + ks.setKeyEntry("Whatever", privateKey, passphrase, chain); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + // create SSL context + SSLContext ctx = SSLContext.getInstance(protocol); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return ctx; + } + + // Certificate-building helper methods. + + protected static void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + KeyPair caKeys = kpg.generateKeyPair(); + serverKeys = kpg.generateKeyPair(); + clientKeys = kpg.generateKeyPair(); + + trustedCert = createTrustedCert(caKeys); + + serverCert = customCertificateBuilder( + serverCertSubjectName, + serverKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), "SHA256withECDSA"); + + clientCert = customCertificateBuilder( + clientCertSubjectName, + clientKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), "SHA256withECDSA"); + } + + private static X509Certificate createTrustedCert(KeyPair caKeys) + throws Exception { + return customCertificateBuilder( + "O=CA-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(true, true, 1) + .build(null, caKeys.getPrivate(), "SHA256withECDSA"); + } + + private static CertificateBuilder customCertificateBuilder( + String subjectName, PublicKey publicKey, PublicKey caKey) + throws CertificateException, IOException { + return new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setNotBefore( + Date.from(Instant.now().minus(1, ChronoUnit.HOURS))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) + .setSerialNumber(BigInteger.valueOf( + new SecureRandom().nextLong(1000000) + 1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey) + .addKeyUsageExt(new boolean[]{ + true, true, true, true, true, true, true}); + } +} diff --git a/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java b/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java index c4905cd5eb1c..8b3a23985726 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. */ -/** +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; + +/* * @test * @summary DNSName parsing tests - * @bug 8213952 8186143 + * @bug 8213952 8186143 8381771 + * @library /test/lib * @modules java.base/sun.security.x509 - * @run testng DNSNameTest + * @run main DNSNameTest */ -import java.io.IOException; -import sun.security.x509.DNSName; +public class DNSNameTest { -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + 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 + ); -import static org.testng.Assert.*; + private static final List GOOD_SAN_NAMES = Stream.concat( + Stream.of( + "*.domain.com", // wildcard in 1st level subdomain + "*.com"), + GOOD_NAMES.stream()) + .toList(); -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 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 + ); - @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; - } + 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(); - @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; + 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); } - - @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 b0d44702d478..9a1aea54ee2e 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.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 @@ public String toString() { 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 b173d345596d..861b717bea0a 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.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 static Path createInputRuntimeImage() { 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 static Path createInputRuntimeImage(RuntimeImageType role) { } }); - 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 static Path createInputRuntimeImage(RuntimeImageType role) { // 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 @@ private static boolean isFakeRuntime(Path runtimeDir) { } 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 JPackageCommand ignoreDefaultRuntime(boolean v) { } 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 @@ private JPackageCommand adjustArgumentsBeforeExecution() { // 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 @@ void useProcess() { } 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); - } - default -> { - throw ExceptionBox.reachedUnreachable(); + yield TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast); } - } + }; } ToolProviderSource() { @@ -2088,7 +2082,7 @@ private enum DefaultToolProviderKey { // 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 66462bedfd71..dc8d79ca8411 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 @@ private static void verifyDesktopFile(JPackageCommand cmd, Optional { - 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 4e0d57631b9f..1ad0116bda7d 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 @@ private static Set createBundleContents(String... customItems) { )).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 81e5da34140a..4c7e3872ed48 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 @@ private String validatedUserName() { 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 0e581c1e7dc6..b512f16497fe 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 @@ private static Collection expectLauncherShortcuts(JPackageCommand cmd, 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 ce3aa6f80e18..edead8b5601e 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 Builder exit() { } 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 65f9c71a9107..48c3b97c77be 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 void testValid(TestConfig cfg) { 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 d7a6f0e714dc..50925d8510de 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 void test_unbox_Error() { 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 @@ private void trace(String format, Object... args) { 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 dbb78d2416c3..67d4258786ba 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.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 @@ private static FailedCommandErrorValidator buildSignCommandErrorValidator(SignKe 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()); - } - default -> { - throw ExceptionBox.reachedUnreachable(); + yield String.format("'%s'", option.asCmdlineArgs().getLast()); } - } + }; 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 ef8f277e2675..fcb1c76fd50f 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 @@ void applyToMainLauncher(LauncherShortcut shortcut, JPackageCommand cmd) { 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 2ef7f95398e8..ccafd2c7b21d 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -767,6 +767,11 @@ record AppTestSpec(String appDesc, TestSpec spec) { 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 ba0f5663d453..a370b755dc4e 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -873,20 +873,16 @@ public static Collection testMacPkgSignWithoutIdentity() { 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 b14d70cc8f36..d28753b4746f 100644 --- a/test/jdk/tools/jpackage/share/ModularAppTest.java +++ b/test/jdk/tools/jpackage/share/ModularAppTest.java @@ -152,10 +152,9 @@ private static Path bakeModuleInRuntime(JavaAppDesc appDesc, RuntimeType runtime 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 @@ private static Path bakeModuleInRuntime(JavaAppDesc appDesc, RuntimeType runtime 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 @@ void run() { 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 f5811596f751..5c2f5beb731b 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 700099656e89..fc3f22261002 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 1a831a0dde37..b28670c98397 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 07ab6937c07f..6734464e7239 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/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java b/test/langtools/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java new file mode 100644 index 000000000000..72b1de22cd2b --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java @@ -0,0 +1,229 @@ +/* + * 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 8373922 + * @summary Enhance Taglet API to support relative URLs + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestRelativeURLTaglet + */ + +import java.net.URI; +import java.nio.file.Path; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.UnknownBlockTagTree; +import com.sun.source.doctree.UnknownInlineTagTree; +import javadoc.tester.JavadocTester; +import jdk.javadoc.doclet.Taglet; +import toolbox.ModuleBuilder; +import toolbox.ToolBox; + +public class TestRelativeURLTaglet extends JavadocTester implements Taglet { + + public static void main(String... args) throws Exception { + new TestRelativeURLTaglet().runTests(); + } + + ToolBox tb = new ToolBox(); + + @Test + public void testRelativePackageURL(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + package p.q; + /** + * First {@test sentence}. + */ + public interface A {} + """, + """ + package p.q.r; + /** + * Comment {@test with} inline {@test tags}. + * + * @test 123 + * @test 456 + */ + public class C {} + """); + tb.writeFile(src.resolve("p/q/doc-files/test.html"), """ + + + HTML {@test file} with {@test inline} tags. + + + """); + + javadoc("-d", base.resolve("out").toString(), + "--source-path", src.toString(), + "-tagletpath", System.getProperty("test.class.path"), + "-taglet", "TestRelativeURLTaglet", + "-subpackages", "p"); + checkExit(Exit.OK); + + checkOutput("p/q/A.html", true, + "First ../../sentence."); + checkOutput("p/q/package-summary.html", true, + "First ../../sentence."); + checkOutput("p/q/doc-files/test.html", true, + "HTML ../../../file with ../../../inline tags."); + checkOutput("p/q/r/C.html", true, + "Comment ../../../with inline ../../../tags.", + "../../../123 ../../../456"); + checkOutput("p/q/r/package-summary.html", true, + "Comment ../../../with inline ../../../tags."); + checkOutput("index-all.html", true, + "First sentence.", + "Comment with inline tags."); + checkOutput("allclasses-index.html", true, + "First sentence.", + "Comment with inline tags."); + } + + @Test + public void testRelativeModuleURL(Path base) throws Exception { + Path src = base.resolve("src"); + new ModuleBuilder(tb, "ma") + .comment("Module {@test ma}.") + .classes( + """ + /** + * Package {@test ma/p/a}. + */ + package p.a; + """, + """ + package p.a; + /** + * Class in {@test ma/p/a}. + * + * @test block1 + * @test block2 + */ + public class A {} + """) + .exports("p.a") + .write(src); + + javadoc("-d", base.resolve("out").toString(), + "--module-source-path", src.toString(), + "-tagletpath", System.getProperty("test.class.path"), + "-taglet", "TestRelativeURLTaglet", + "--module", "ma"); + checkExit(Exit.OK); + + checkOutput("ma/p/a/package-summary.html", true, + "Package ../../../ma/p/a.", + "Class in ../../../ma/p/a."); + checkOutput("ma/p/a/A.html", true, + "Class in ../../../ma/p/a.", + "
          ../../../block1 ../../../block2
          "); + checkOutput("ma/module-summary.html", true, + "Module ../ma.", + "Package ../ma/p/a."); + checkOutput("index-all.html", true, + "Class in ma/p/a.", + "Module ma.", + "Package ma/p/a."); + } + + @Test + public void testUnnamedPackageURL(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + /** + * Class in unnamed package: {@test tag}. + * + * @test first + * @test second + */ + public class C {} + """); + + javadoc("-d", base.resolve("out").toString(), + "--source-path", src.toString(), + "-tagletpath", System.getProperty("test.class.path"), + "-taglet", "TestRelativeURLTaglet", + src.resolve("C.java").toString()); + checkExit(Exit.OK); + + checkOutput("C.html", true, + "Class in unnamed package: tag.", + "
          first second
          "); + checkOutput("index-all.html", true, + "Class in unnamed package: tag."); + checkOutput("allclasses-index.html", true, + "Class in unnamed package: tag."); + } + + // Taglet implementation + + @Override + public Set getAllowedLocations() { + return EnumSet.allOf(Location.class); + } + + @Override + public boolean isInlineTag() { + return true; + } + + @Override + public boolean isBlockTag() { + return true; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public String toString(List tags, Element element, URI docRoot) { + if (tags.size() == 1 && tags.getFirst() instanceof UnknownInlineTagTree uit) { + return docRoot.resolve(uit.getContent().toString()).toString(); + } else { + return tags.stream() + .map(t -> docRoot.resolve(((UnknownBlockTagTree) t).getContent().toString()).toString()) + .collect(Collectors.joining(" ")); + } + } + + @Override + public String toString(List tags, Element element) { + throw new UnsupportedOperationException(); + } +} + 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 000000000000..29c0c50f4d81 --- /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 2b89e8d9d806..002b68027f7e 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/TextBlockU2028.java b/test/langtools/tools/javac/TextBlockU2028.java new file mode 100644 index 000000000000..a7abfe432634 --- /dev/null +++ b/test/langtools/tools/javac/TextBlockU2028.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 + * @bug 8380912 + * @summary Verify that trailing whitespace warning is not reported for \u2028 + * inside text block content + * @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 TextBlockU2028 + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.JavacTask; +import toolbox.ToolBox; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +public class TextBlockU2028 { + Path base; + ToolBox tb = new ToolBox(); + + @Test + void testNoFalseTrailingWhitespaceWarning() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .options("-d", classes.toString(), "-Xlint:text-blocks", "-XDrawDiagnostics", "-Werror") + .sources(""" + public class Test { + String s = \"\"\" + foo \\u2028 bar + \"\"\"; + } + """) + .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 000000000000..05c17dcfb031 --- /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 368fe8bd808c..6c4e199e19bd 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 268ad85aa813..98dc8fedfd7a 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 e604ca167b79..872de721f455 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 0f58e5e40545..f12eb9799ecc 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 18bf4f7937d6..8994936d0ec9 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 5823c894bc48..90c001bcf122 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 03831725452e..21a26fb9e7af 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 000000000000..b2c8a10c0acb --- /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 000000000000..55003e62fb85 --- /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 000000000000..1b0497dfcb0d --- /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 000000000000..3977e6318ef8 --- /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 000000000000..c2ec7d370d97 --- /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 000000000000..91aff9bb9480 --- /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 000000000000..c271a4898134 --- /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 700099656e89..fc3f22261002 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 2a5caedc8d85..6598210d4ebd 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 3eac8a35a375..80ff54021f5e 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 35cee7508221..049226545922 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 a8bba9c76e27..73e45711fe91 100644 --- a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java @@ -211,4 +211,22 @@ public SimpleCDSAppTester run(String args[]) throws Exception { 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 5f5d513a8b28..97d6542ec3b3 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 SystemdRunOptions cpuLimit(String cpuLimit) { 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 9acff93aaca2..5a868b8cd2a7 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 @@ private static String sliceFileName(String sliceName) { 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 @@ private static List buildJavaCommand(SystemdRunOptions opts) throws Exce 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); diff --git a/test/lib/jdk/test/lib/security/SecurityUtils.java b/test/lib/jdk/test/lib/security/SecurityUtils.java index be6ff1cc0e39..78dc2aa27291 100644 --- a/test/lib/jdk/test/lib/security/SecurityUtils.java +++ b/test/lib/jdk/test/lib/security/SecurityUtils.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 @@ -23,8 +23,10 @@ package jdk.test.lib.security; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.PrintStream; import java.nio.ByteBuffer; import java.security.KeyStore; import java.security.Security; @@ -219,5 +221,40 @@ public static int getInt16(ByteBuffer m) throws IOException { return ((m.get() & 0xFF) << 8) | (m.get() & 0xFF); } + // Helper method to run and get log. + public static String runAndGetLog(Runnable runnable) { + System.setProperty("javax.net.debug", "ssl"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream err = new PrintStream(baos); + PrintStream origErr = System.err; + System.setErr(err); + + runnable.run(); + err.close(); + + // Save the log output and then print it as usual. + String log = baos.toString(); + System.setErr(origErr); + System.err.print(log); + return log; + } + + // Helper method to find log messages. + public static int countSubstringOccurrences(String str, String sub) { + if (str == null || sub == null || sub.isEmpty()) { + return 0; + } + + int count = 0; + int lastIndex = 0; + + while ((lastIndex = str.indexOf(sub, lastIndex)) != -1) { + count++; + lastIndex += sub.length(); + } + + return count; + } + private SecurityUtils() {} }