diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000000000..0885752ac1907 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,67 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle + +name: Java CI with Gradle + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. + # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md + - name: Setup Gradle + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + + - name: Build with Gradle Wrapper + run: ./gradlew build + + # NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html). + # If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version. + # + # - name: Setup Gradle + # uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + # with: + # gradle-version: '8.9' + # + # - name: Build with Gradle 8.9 + # run: gradle build + + dependency-submission: + + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. + # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md + - name: Generate and submit dependency graph + uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000000000..c6bb03654faa5 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,35 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + - name: Update dependency graph + uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml new file mode 100644 index 0000000000000..e64c58f5d3d1e --- /dev/null +++ b/.github/workflows/mdbook.yml @@ -0,0 +1,60 @@ +# Sample workflow for building and deploying a mdBook site to GitHub Pages +# +# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html +# +name: Deploy mdBook site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["master"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + env: + MDBOOK_VERSION: 0.4.36 + steps: + - uses: actions/checkout@v4 + - name: Install mdBook + run: | + curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh + rustup update + cargo install --version ${MDBOOK_VERSION} mdbook + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + - name: Build with mdBook + run: mdbook build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./book + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 7b198f976793f..b7754326c975c 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -1228,7 +1228,7 @@ private static Stream zidMapEntry() { String zone001 = handlerMetaZones.zidMap().get(meta); return zone001 == null ? "" : String.format(" \"%s\", \"%s\", \"%s\",", - id, meta, zone001); + escape(id), escape(meta), escape(zone001)); }) .filter(s -> !s.isEmpty()) .sorted(); diff --git a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java index 45de46d247690..9d699cc8a749d 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java @@ -102,9 +102,9 @@ public void startElement(String uri, String localName, String qName, Attributes zones.put(attributes.getValue("other"), attributes.getValue("type")); } else { mzoneMapEntryList.add(String.format(" \"%s\", \"%s\", \"%s\",", - attributes.getValue("other"), - territory, - attributes.getValue("type"))); + CLDRConverter.escape(attributes.getValue("other")), + CLDRConverter.escape(territory), + CLDRConverter.escape(attributes.getValue("type")))); } pushIgnoredContainer(qName); break; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 0bc5a2bdb0dff..84657ae94f00b 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -103,14 +103,14 @@ public void generateBundle(String packageName, String baseName, String localeID, for (String key : map.keySet()) { if (key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) { String meta = key.substring(CLDRConverter.METAZONE_ID_PREFIX.length()); - String[] value; - value = (String[]) map.get(key); - fmt.format(" final String[] %s = new String[] {\n", meta); - for (String s : value) { - fmt.format(" \"%s\",\n", CLDRConverter.escape(s)); + if (map.get(key) instanceof String[] value) { + fmt.format(" final String[] %s = new String[] {\n", CLDRConverter.escape(meta)); + for (String s : value) { + fmt.format(" \"%s\",\n", CLDRConverter.escape(s)); + } + fmt.format(" };\n"); + metaKeys.add(key); } - fmt.format(" };\n"); - metaKeys.add(key); } } for (String key : metaKeys) { @@ -143,15 +143,15 @@ public void generateBundle(String packageName, String baseName, String localeID, if (fmt == null) { fmt = new Formatter(); } - String metaVal = oldEntry.metaKey(); + String metaVal = CLDRConverter.escape(oldEntry.metaKey()); if (val instanceof String[] values) { fmt.format(" final String[] %s = new String[] {\n", metaVal); for (String s : values) { fmt.format(" \"%s\",\n", CLDRConverter.escape(s)); } fmt.format(" };\n"); - } else { - fmt.format(" final String %s = \"%s\";\n", metaVal, CLDRConverter.escape((String)val)); + } else if (val instanceof String str) { + fmt.format(" final String %s = \"%s\";\n", metaVal, CLDRConverter.escape(str)); } newMap.put(oldEntry.key, oldEntry.metaKey()); } @@ -178,21 +178,21 @@ public void generateBundle(String packageName, String baseName, String localeID, out.println(" final Object[][] data = new Object[][] {"); for (String key : map.keySet()) { Object value = map.get(key); + var keyStr = CLDRConverter.escape(key); if (value == null) { CLDRConverter.warning("null value for " + key); - } else if (value instanceof String) { - String valStr = (String)value; + } else if (value instanceof String valStr) { + var escapedVal = CLDRConverter.escape(valStr); if (type == BundleType.TIMEZONE && !(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) || valStr.startsWith(META_VALUE_PREFIX)) { - out.printf(" { \"%s\", %s },\n", key, CLDRConverter.escape(valStr)); + out.printf(" { \"%s\", %s },\n", keyStr, escapedVal); } else { - out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.escape(valStr)); + out.printf(" { \"%s\", \"%s\" },\n", keyStr, escapedVal); } - } else if (value instanceof String[]) { - String[] values = (String[]) value; - out.println(" { \"" + key + "\",\n new String[] {"); + } else if (value instanceof String[] values) { + out.println(" { \"" + keyStr + "\",\n new String[] {"); for (String s : values) { out.println(" \"" + CLDRConverter.escape(s) + "\","); } @@ -311,7 +311,7 @@ public class %s implements LocaleDataMetaInfo { out.printf(" parentLocalesMap.put(Locale.ROOT,\n"); } else { out.printf(" parentLocalesMap.put(Locale.forLanguageTag(\"%s\"),\n", - parentTag); + CLDRConverter.escape(parentTag)); } generateStringArray(metaInfo.get(key), out); } @@ -320,7 +320,7 @@ public class %s implements LocaleDataMetaInfo { // for languageAliasMap CLDRConverter.handlerSupplMeta.getLanguageAliasData().forEach((key, value) -> { - out.printf(" languageAliasMap.put(\"%s\", \"%s\");\n", key, value); + out.printf(" languageAliasMap.put(\"%s\", \"%s\");\n", CLDRConverter.escape(key), CLDRConverter.escape(value)); }); out.printf(" }\n\n"); @@ -338,11 +338,11 @@ private static class CLDRMapHolder { CLDRConverter.handlerTimeZone.getData().entrySet().stream() .forEach(e -> { String[] ids = ((String)e.getValue()).split("\\s"); - out.printf(" tzCanonicalIDMap.put(\"%s\", \"%s\");\n", e.getKey(), - ids[0]); + out.printf(" tzCanonicalIDMap.put(\"%s\", \"%s\");\n", CLDRConverter.escape(e.getKey()), + CLDRConverter.escape(ids[0])); for (int i = 1; i < ids.length; i++) { - out.printf(" tzCanonicalIDMap.put(\"%s\", \"%s\");\n", ids[i], - ids[0]); + out.printf(" tzCanonicalIDMap.put(\"%s\", \"%s\");\n", CLDRConverter.escape(ids[i]), + CLDRConverter.escape(ids[0])); } }); out.println(); @@ -352,8 +352,9 @@ private static class CLDRMapHolder { if (key.startsWith(CLDRConverter.LIKELY_SCRIPT_PREFIX)) { // ensure spaces at the begin/end for delimiting purposes out.printf(" likelyScriptMap.put(\"%s\", \"%s\");\n", - key.substring(CLDRConverter.LIKELY_SCRIPT_PREFIX.length()), - " " + metaInfo.get(key).stream().collect(Collectors.joining(" ")) + " "); + CLDRConverter.escape(key.substring(CLDRConverter.LIKELY_SCRIPT_PREFIX.length())), + " " + metaInfo.get(key).stream() + .map(l -> CLDRConverter.escape(l)).collect(Collectors.joining(" ")) + " "); } } out.printf(" }\n }\n"); @@ -371,7 +372,7 @@ public String availableLanguageTags(String category) { return " %s"; } """, - toLocaleList(applyLanguageAliases(metaInfo.get("AvailableLocales")), false)); + CLDRConverter.escape(toLocaleList(applyLanguageAliases(metaInfo.get("AvailableLocales")), false))); if(CLDRConverter.isBaseModule) { out.printf(""" @@ -408,7 +409,7 @@ private static void generateStringArray(SortedSet set, PrintWriter out) int count = 0; for (int i = 0; i < children.length; i++) { String child = children[i]; - out.printf("\"%s\", ", child); + out.printf("\"%s\", ", CLDRConverter.escape(child)); count += child.length() + 4; if (i != children.length - 1 && count > 64) { out.printf("\n "); diff --git a/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java index 101ee81b2560e..35e1cef1e87c9 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, 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 @@ -85,7 +85,9 @@ public void startElement(String uri, String localName, String qName, Attributes public Stream deprecatedMap() { return keySet().stream() - .map(k -> String.format(" \"%s\", \"%s\",", k, get(k))) + .map(k -> " \"%s\", \"%s\",".formatted( + CLDRConverter.escape(k), + CLDRConverter.escape((String)get(k)))) .sorted(); } Map getLanguageAliasData() { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 3bb4030afdeda..540b24f5c78ec 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -268,26 +268,36 @@ class nmethod : public CodeBlob { volatile signed char _state; // {not_installed, in_use, not_entrant} public: - union Flags { - uint8_t _raw; - struct { - bool _has_unsafe_access:1; // May fault due to unsafe access. - bool _has_wide_vectors:1; // Preserve wide vectors at safepoints - bool _has_monitors:1; // Fastpath monitor detection for continuations - bool _has_scoped_access:1; // Used by shared scope closure (scopedMemoryAccess.cpp) + struct Flags { + uint8_t const _bits; + + enum : uint8_t { + UNSAFE_ACCESS = 1 << 0, + WIDE_VECTORS = 1 << 1, + MONITORS = 1 << 2, + SCOPED_ACCESS = 1 << 3 }; - Flags() { - _raw = 0; - } - Flags(bool has_unsafe_access, bool has_wide_vectors, bool has_monitors, bool has_scoped_access) : Flags() { - _has_unsafe_access = has_unsafe_access; - _has_wide_vectors = has_wide_vectors; - _has_monitors = has_monitors; - _has_scoped_access = has_scoped_access; - } - }; - static_assert(sizeof(Flags) == sizeof(uint8_t), "Must fit exactly"); + Flags() : _bits(0) {} + Flags(bool has_unsafe_access, bool has_wide_vectors, bool has_monitors, bool has_scoped_access) : + _bits((has_unsafe_access ? UNSAFE_ACCESS : 0) | + (has_wide_vectors ? WIDE_VECTORS : 0) | + (has_monitors ? MONITORS : 0) | + (has_scoped_access ? SCOPED_ACCESS : 0)) + {} + + // May fault due to unsafe access + bool has_unsafe_access() const { return (_bits & UNSAFE_ACCESS) != 0; } + + // Preserve wide vectors at safepoints + bool has_wide_vectors() const { return (_bits & WIDE_VECTORS) != 0; } + + // Fastpath monitor detection for continuations + bool has_monitors() const { return (_bits & MONITORS) != 0; } + + // Used by shared scope closure (scopedMemoryAccess.cpp) + bool has_scoped_access() const { return (_bits & SCOPED_ACCESS) != 0; } + }; private: // Persistent bits, set once during construction. @@ -779,10 +789,10 @@ class nmethod : public CodeBlob { template void set_gc_data(T* gc_data) { _gc_data = reinterpret_cast(gc_data); } - bool has_unsafe_access() const { return _flags._has_unsafe_access; } - bool has_monitors() const { return _flags._has_monitors; } - bool has_scoped_access() const { return _flags._has_scoped_access; } - bool has_wide_vectors() const { return _flags._has_wide_vectors; } + bool has_unsafe_access() const { return _flags.has_unsafe_access(); } + bool has_monitors() const { return _flags.has_monitors(); } + bool has_scoped_access() const { return _flags.has_scoped_access(); } + bool has_wide_vectors() const { return _flags.has_wide_vectors(); } bool has_flushed_dependencies() const { return _has_flushed_dependencies; } void set_has_flushed_dependencies(bool z) { diff --git a/src/hotspot/share/runtime/sharedRuntimeTrans.cpp b/src/hotspot/share/runtime/sharedRuntimeTrans.cpp index 416c8584751fd..2de3439e0a09d 100644 --- a/src/hotspot/share/runtime/sharedRuntimeTrans.cpp +++ b/src/hotspot/share/runtime/sharedRuntimeTrans.cpp @@ -442,8 +442,8 @@ bp[] = {1.0, 1.5,}, cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ - ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ - ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + ivln2_h = 1.4426946640014648438, /* 0x3FF71547, 0x00000000 =21b 1/ln2*/ + ivln2_l = 3.7688749856360991145e-07; /* 0x3E994AE0, 0xBF85DDF4 =1/ln2 tail*/ ATTRIBUTE_NO_UBSAN static double __ieee754_pow(double x, double y) { diff --git a/src/java.base/share/classes/java/lang/FdLibm.java b/src/java.base/share/classes/java/lang/FdLibm.java index 5a6bdc9b94e99..4285026946749 100644 --- a/src/java.base/share/classes/java/lang/FdLibm.java +++ b/src/java.base/share/classes/java/lang/FdLibm.java @@ -29,7 +29,8 @@ /** * Port of the "Freely Distributable Math Library", version 5.3, from - * C to Java. + * C to Java, with a fix to pow so that its error bounds conform to + * the quality of implementation criteria for the method. * *

The C version of fdlibm relied on the idiom of pointer aliasing * a 64-bit double floating-point value as a two-element array of @@ -2207,8 +2208,8 @@ else if (y_abs >= 1.0) { // |y| >= 1.0 // |y| is huge if (y_abs > 0x1.00000_ffff_ffffp31) { // if |y| > ~2**31 final double INV_LN2 = 0x1.7154_7652_b82fep0; // 1.44269504088896338700e+00 = 1/ln2 - final double INV_LN2_H = 0x1.715476p0; // 1.44269502162933349609e+00 = 24 bits of 1/ln2 - final double INV_LN2_L = 0x1.4ae0_bf85_ddf44p-26; // 1.92596299112661746887e-08 = 1/ln2 tail + final double INV_LN2_H = 0x1.7154_7p+0; // 1.4426946640014648438 = 21 bits of 1/ln2 + final double INV_LN2_L = 0x1.94ae_0bf8_5ddf4p-22; // 3.7688749856360991145e-07 = 1/ln2 tail // Over/underflow if x is not close to one if (x_abs < 0x1.fffff_0000_0000p-1) // |x| < ~0.9999995231628418 diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index a8f67ef58ba80..6aab491182a9f 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -66,8 +66,9 @@ * * *

The Java math library is defined with respect to - * {@code fdlibm} version 5.3. Where {@code fdlibm} provides - * more than one definition for a function (such as + * {@code fdlibm} version 5.3 with a fix to {@code pow} so that its error bounds + * conform to the quality of implementation criteria for {@code pow}. + * Where {@code fdlibm} provides more than one definition for a function (such as * {@code acos}), use the "IEEE 754 core function" version * (residing in a file whose name begins with the letter * {@code e}). The methods which require {@code fdlibm} diff --git a/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/src/java.desktop/share/classes/sun/awt/SunToolkit.java index 238ca32bd2931..23ec5f54959a1 100644 --- a/src/java.desktop/share/classes/sun/awt/SunToolkit.java +++ b/src/java.desktop/share/classes/sun/awt/SunToolkit.java @@ -1787,34 +1787,20 @@ public void dismissPopupOnFocusLostIfNeeded(Window invoker) {} public void dismissPopupOnFocusLostIfNeededCleanUp(Window invoker) {} - - private static final Object DEACTIVATION_TIMES_MAP_KEY = new Object(); + private static WeakHashMap activationMap = null; public synchronized void setWindowDeactivationTime(Window w, long time) { - AppContext ctx = getAppContext(w); - if (ctx == null) { - return; - } - @SuppressWarnings("unchecked") - WeakHashMap map = (WeakHashMap)ctx.get(DEACTIVATION_TIMES_MAP_KEY); - if (map == null) { - map = new WeakHashMap(); - ctx.put(DEACTIVATION_TIMES_MAP_KEY, map); + if (activationMap == null) { + activationMap = new WeakHashMap(); } - map.put(w, time); + activationMap.put(w, time); } public synchronized long getWindowDeactivationTime(Window w) { - AppContext ctx = getAppContext(w); - if (ctx == null) { - return -1; - } - @SuppressWarnings("unchecked") - WeakHashMap map = (WeakHashMap)ctx.get(DEACTIVATION_TIMES_MAP_KEY); - if (map == null) { + if (activationMap == null) { return -1; } - Long time = map.get(w); + Long time = activationMap.get(w); return time == null ? -1 : time; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java index 466654180ebf7..f4b20aeec03c7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java @@ -222,7 +222,7 @@ public boolean stop() { * @return recording settings, not {@code null} */ public Map getSettings() { - return new HashMap<>(internal.getSettings()); + return internal.getSettingsCopy(); } /** diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java index 21079fab3a912..d3765af8e6c25 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, 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 @@ -25,7 +25,6 @@ package jdk.jfr.internal; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -92,7 +91,7 @@ public static void updateSettingPathToGcRoots(Map s, Boolean pat } public static Map createSettingsForSnapshot(PlatformRecording recording, Boolean pathToGcRoots) { - Map settings = new HashMap<>(recording.getSettings()); + Map settings = recording.getSettingsCopy(); updateSettingPathToGcRoots(settings, pathToGcRoots); return settings; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java index a82eff239e660..4779b8e0125b9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java @@ -585,7 +585,7 @@ synchronized Recording newCopy(PlatformRecording r, boolean stop) { boolean register = !isDestroyed() && r.getState() != RecordingState.CLOSED; Recording newRec = access.newRecording(register); PlatformRecording copy = access.getPlatformRecording(newRec); - copy.setSettings(r.getSettings()); + copy.setSettings(r.getSettingsCopy()); copy.setMaxAge(r.getMaxAge()); copy.setMaxSize(r.getMaxSize()); copy.setDumpOnExit(r.getDumpOnExit()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index 92d60f5bdec1f..407e353b0519b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -253,9 +253,14 @@ void scheduleStart(Instant startTime) { } } - public Map getSettings() { + Map getSettings() { + assert Thread.holdsLock(recorder) : "Must have recorder lock when accessing recorder.settings"; + return settings; + } + + public Map getSettingsCopy() { synchronized (recorder) { - return settings; + return new LinkedHashMap<>(settings); } } @@ -371,7 +376,7 @@ public PlatformRecording newSnapshotClone(String reason, Boolean pathToGcRoots) clone.setStartTime(getStartTime()); } if (pathToGcRoots == null) { - clone.setSettings(getSettings()); // needed for old object sample + clone.setSettings(getSettingsCopy()); // needed for old object sample clone.stop(reason); // dumps to destination path here } else { // Risk of violating lock order here, since diff --git a/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java b/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java index e28cc5ab34631..a78a38fc807b0 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java +++ b/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java @@ -45,6 +45,14 @@ public class PowDNodeTests { public static final double B = UNIFORMS.next() * 1000.0d; public static final double E = UNIFORMS.next() * 1000.0d + 3.0d; // e >= 3 to avoid strength reduction code + private static final double REG1_B = 0x1.000002c5e2e99p+0; + private static final double REG1_E = 0x1.c9eee35374af6p+31; + private static final double REG1_R = 0x1.ffffe0bc9e399p+915; + + private static final double REG2_B = 0x1.fffff4e900013p-1; + private static final double REG2_E = 0x1.0000100000001p+31; + private static final double REG2_R = 0x0.421378008b246p-1022; + public static void main(String[] args) { TestFramework.run(); @@ -164,6 +172,20 @@ public static double lateBothConstant() { return Math.pow(base, exp); } + // Test 12: pow(REG1_B, REG1_E) -> REG1_R + @Test + @IR(failOn = {IRNode.POW_D}) + public static double regressionHugeExpAboveOne() { + return Math.pow(REG1_B, REG1_E); + } + + // Test 13: pow(REG2_B, REG2_E) -> REG2_R + @Test + @IR(failOn = {IRNode.POW_D}) + public static double regressionHugeExpBelowOne() { + return Math.pow(REG2_B, REG2_E); + } + private static void assertEQWithinOneUlp(double expected, double observed) { if (Double.isNaN(expected) && Double.isNaN(observed)) return; @@ -214,5 +236,8 @@ private static void testCorrectness() { assertEQWithinOneUlp(StrictMath.pow(b, e), nonConstant(b, e)); } } + + assertEQWithinOneUlp(REG1_R, regressionHugeExpAboveOne()); + assertEQWithinOneUlp(REG2_R, regressionHugeExpBelowOne()); } } diff --git a/test/jdk/java/lang/StrictMath/PowTests.java b/test/jdk/java/lang/StrictMath/PowTests.java index 90482b264feb0..d38041cdce952 100644 --- a/test/jdk/java/lang/StrictMath/PowTests.java +++ b/test/jdk/java/lang/StrictMath/PowTests.java @@ -301,6 +301,18 @@ private static int testPow() { 5.0, 55.901699437494756 }, + + { + 0x1.000002c5e2e99p+0, // |x| > 1 + 0x1.c9eee35374af6p+31, // |y| huge + 0x1.ffffe0bc9e399p+915 + }, + + { + 0x1.fffff4e900013p-1, // |x| < 1 + 0x1.0000100000001p+31, // |y| huge + 0x0.421378008b246p-1022 + }, }; for (double[] testCase: testCases) diff --git a/test/jdk/javax/accessibility/awt/ButtonTest.java b/test/jdk/javax/accessibility/awt/ButtonTest.java new file mode 100644 index 0000000000000..6164c2fd7a8ee --- /dev/null +++ b/test/jdk/javax/accessibility/awt/ButtonTest.java @@ -0,0 +1,115 @@ +/* + * 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 + * 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 headful + * @summary Regression Test: javax.accessibility, Button + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main ButtonTest + */ + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; + +public class ButtonTest { + + static Button button; + final String accName = "Button Test"; + final String accDesc = "Regression Test: javax.accessibility, Button"; + final AccessibleRole role = AccessibleRole.PUSH_BUTTON; + static Frame frame; + + public void createGUI() { + frame = new Frame("ButtonTest"); + button = new Button("This is a Button!"); + AccessibleContext ac = button.getAccessibleContext(); + + ac.setAccessibleName(accName); + ac.setAccessibleDescription(accDesc); + + frame.add(button); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException, AWTException { + + ButtonTest buttonTest = new ButtonTest(); + EventQueue.invokeAndWait(buttonTest::createGUI); + + Robot rbt = new Robot(); + rbt.waitForIdle(); + rbt.delay(5000); + + try { + EventQueue.invokeAndWait(buttonTest::test); + } finally { + buttonTest.dispose(); + } + } + + private void dispose() + throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + public Component getComponent() { + return button; + } + + public void test() { + Button b = (Button) getComponent(); + + AccessibleContext ac = b.getAccessibleContext(); + AccessibleStateSet aset = ac.getAccessibleStateSet(); + if (aset == null) { + throw new RuntimeException("getAccessibleStateSet should not return null"); + } + AccessibleStateSetTester astr = + new AccessibleStateSetTester(b, aset); + astr.testAll(); + + AccessibleTestUtils.verifyButtonAccessibility( + b, + accName, + accDesc + ); + } +} diff --git a/test/jdk/javax/accessibility/awt/ChoiceTest.java b/test/jdk/javax/accessibility/awt/ChoiceTest.java new file mode 100644 index 0000000000000..59ca688a7e340 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/ChoiceTest.java @@ -0,0 +1,123 @@ +/* + * 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 + * 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 headful + * @summary Regression Test: javax.accessibility, Choice + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main ChoiceTest + */ + +import java.awt.AWTException; +import java.awt.Choice; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import java.util.Locale; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; + +public class ChoiceTest { + + static Choice choice; + final String accName = "Choice Test"; + final String accDesc = "Regression Test: javax.accessibility, Choice"; + final AccessibleRole role = AccessibleRole.COMBO_BOX; + static Frame frame; + + public void createGUI() { + frame = new Frame("Choice Test"); + choice = new Choice(); + choice.add("One"); + choice.add("Two"); + choice.add("Three"); + + AccessibleContext ac = choice.getAccessibleContext(); + ac.setAccessibleName(accName); + ac.setAccessibleDescription(accDesc); + + frame.add(choice); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException, AWTException { + + ChoiceTest choiceTest = new ChoiceTest(); + EventQueue.invokeAndWait(choiceTest::createGUI); + + Robot rbt = new Robot(); + rbt.waitForIdle(); + rbt.delay(5000); + + try { + EventQueue.invokeAndWait(choiceTest::test); + } finally { + choiceTest.dispose(); + } + + } + + private void dispose() + throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + public Component getComponent() { + return choice; + } + + public void test() { + Choice c = (Choice) getComponent(); + + // If you want to keep using AccessibleStateSetTester explicitly: + AccessibleContext ac = c.getAccessibleContext(); + AccessibleStateSet aset = ac.getAccessibleStateSet(); + if (aset == null) { + throw new RuntimeException( + "getAccessibleStateSet should not return a null value"); + } + AccessibleStateSetTester astr = + new AccessibleStateSetTester(c, aset); + astr.testAll(); + + // All remaining checks (name, desc, role, locale, AccessibleAction, + // AccessibleComponent, selection/text/value) are in one place: + AccessibleTestUtils.verifyChoiceAccessibility( + c, + accName, + accDesc + ); + } +} diff --git a/test/jdk/javax/accessibility/awt/ScrollbarTest.java b/test/jdk/javax/accessibility/awt/ScrollbarTest.java new file mode 100644 index 0000000000000..1e0d1551da467 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/ScrollbarTest.java @@ -0,0 +1,158 @@ +/* + * 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 + * 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 headful + * @summary Scrollbar Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main ScrollbarTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public final class ScrollbarTest { + + private static Scrollbar scrollbar; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Scrollbar Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Scrollbar"; + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException, AWTException { + + ScrollbarTest test = new ScrollbarTest(); + EventQueue.invokeAndWait(test::createGui); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(test::testAccessibility); + } finally { + test.dispose(); + } + } + + private void createGui() { + frame = new Frame("ScrollbarTest"); + scrollbar = new Scrollbar(Scrollbar.VERTICAL, 0, 60, 0, 300); + + AccessibleContext context = scrollbar.getAccessibleContext(); + context.setAccessibleName(ACCESSIBLE_NAME); + context.setAccessibleDescription(ACCESSIBLE_DESCRIPTION); + + frame.add(scrollbar); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private Scrollbar getComponent() { + return scrollbar; + } + + private void testAccessibility() { + Scrollbar component = getComponent(); + + AccessibleTestUtils.verifyScrollbarAccessibility( + component, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + AccessibleStateSet stateSet = component.getAccessibleContext().getAccessibleStateSet(); + if (stateSet == null) { + throw new RuntimeException("getAccessibleStateSet returned null"); + } + + new ScrollAccessibleStateSetTester(component, stateSet).testAll(); + } + + private static final class ScrollAccessibleStateSetTester extends AccessibleStateSetTester { + + private final Scrollbar scrollbar; + private final AccessibleStateSet stateSet; + + private ScrollAccessibleStateSetTester(Scrollbar scrollbar, AccessibleStateSet stateSet) { + super(scrollbar, stateSet); + this.scrollbar = scrollbar; + this.stateSet = stateSet; + } + + @Override + public void testHorizontal() { + if (scrollbar.getOrientation() == Scrollbar.HORIZONTAL) { + if (!stateSet.contains(AccessibleState.HORIZONTAL)) { + throw new RuntimeException( + "Scrollbar is horizontal but AccessibleStateSet does not contain HORIZONTAL" + ); + } + + if (stateSet.contains(AccessibleState.VERTICAL)) { + throw new RuntimeException( + "Scrollbar is horizontal but AccessibleStateSet contains both HORIZONTAL and VERTICAL" + ); + } + } + } + + @Override + public void testVertical() { + if (scrollbar.getOrientation() == Scrollbar.VERTICAL) { + if (!stateSet.contains(AccessibleState.VERTICAL)) { + throw new RuntimeException( + "Scrollbar is vertical but AccessibleStateSet does not contain VERTICAL" + ); + } + + if (stateSet.contains(AccessibleState.HORIZONTAL)) { + throw new RuntimeException( + "Scrollbar is vertical but AccessibleStateSet contains both VERTICAL and HORIZONTAL" + ); + } + } + } + } +} diff --git a/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleComponentTester.java b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleComponentTester.java new file mode 100644 index 0000000000000..ae529b2256701 --- /dev/null +++ b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleComponentTester.java @@ -0,0 +1,198 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.Objects; +import java.util.function.Supplier; + +import javax.accessibility.AccessibleComponent; + +public final class AccessibleComponentTester { + + private final AccessibleComponent accessibleComponent; + private final Component component; + + public AccessibleComponentTester(Component component, AccessibleComponent accessibleComponent) { + this.component = Objects.requireNonNull(component, "component must not be null"); + this.accessibleComponent = Objects.requireNonNull(accessibleComponent, "accessibleComponent must not be null"); + } + + public void test() { + testGetBackground(); + testGetBounds(); + testGetCursor(); + testGetFont(); + testGetForeground(); + testGetLocation(); + testGetLocationOnScreen(); + testGetSize(); + testIsEnabled(); + testIsFocusTraversable(); + testIsShowing(); + testIsVisible(); + } + + public void testGetBackground() { + assertEqual( + "getBackground", + component.getBackground(), + accessibleComponent.getBackground() + ); + } + + public void testGetBounds() { + assertEqual( + "getBounds", + component.getBounds(), + accessibleComponent.getBounds() + ); + } + + public void testGetCursor() { + assertEqual( + "getCursor", + component.getCursor(), + accessibleComponent.getCursor() + ); + } + + public void testGetFont() { + assertEqual( + "getFont", + component.getFont(), + accessibleComponent.getFont() + ); + } + + public void testGetForeground() { + assertEqual( + "getForeground", + component.getForeground(), + accessibleComponent.getForeground() + ); + } + + public void testGetLocation() { + assertEqualWithStateHandling( + "getLocation", + component::getLocation, + accessibleComponent::getLocation + ); + } + + public void testGetLocationOnScreen() { + assertEqualWithStateHandling( + "getLocationOnScreen", + component::getLocationOnScreen, + accessibleComponent::getLocationOnScreen + ); + } + + public void testGetSize() { + assertEqual( + "getSize", + component.getSize(), + accessibleComponent.getSize() + ); + } + + public void testIsEnabled() { + assertBooleanEqual( + "isEnabled", + component.isEnabled(), + accessibleComponent.isEnabled() + ); + } + + public void testIsFocusTraversable() { + assertBooleanEqual( + "isFocusTraversable", + component.isFocusTraversable(), + accessibleComponent.isFocusTraversable() + ); + } + + public void testIsShowing() { + assertBooleanEqual( + "isShowing", + component.isShowing(), + accessibleComponent.isShowing() + ); + } + + public void testIsVisible() { + assertBooleanEqual( + "isVisible", + component.isVisible(), + accessibleComponent.isVisible() + ); + } + + private void assertEqual(String methodName, Object componentValue, Object accessibleValue) { + if (!Objects.equals(componentValue, accessibleValue)) { + throw new RuntimeException(buildMismatchMessage(methodName, componentValue, accessibleValue)); + } + } + + private void assertBooleanEqual(String methodName, boolean componentValue, boolean accessibleValue) { + if (componentValue != accessibleValue) { + throw new RuntimeException( + String.format( + "Mismatch in %s: Component returned [%s], AccessibleComponent returned [%s]", + methodName, componentValue, accessibleValue + ) + ); + } + } + + private void assertEqualWithStateHandling( + String methodName, + Supplier componentSupplier, + Supplier accessibleSupplier + ) { + try { + T componentValue = componentSupplier.get(); + T accessibleValue = accessibleSupplier.get(); + assertEqual(methodName, componentValue, accessibleValue); + } catch (java.awt.IllegalComponentStateException ex) { + throw new RuntimeException( + "Component was not in a valid state when " + methodName + " was called. " + + "This is not necessarily an accessibility issue.", + ex + ); + } + } + + private String buildMismatchMessage(String methodName, Object componentValue, Object accessibleValue) { + return String.format( + "Mismatch in %s: Component returned [%s], AccessibleComponent returned [%s]", + methodName, componentValue, accessibleValue + ); + } +} diff --git a/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleStateSetTester.java b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleStateSetTester.java new file mode 100644 index 0000000000000..2f772859e761c --- /dev/null +++ b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleStateSetTester.java @@ -0,0 +1,318 @@ +/* + * 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 + * 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.Component; +import java.util.Objects; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.swing.JComponent; + +/** + * Validates an {@link AccessibleStateSet} against the state of a component. + * + *

This class provides generic validation for common accessibility states. + * Subclasses can extend it to add component-specific checks.

+ * + *

This works for both Swing and AWT components that implement + * {@link Accessible}.

+ */ +public class AccessibleStateSetTester { + + private final AccessibleStateSet stateSet; + private final Component component; + + public AccessibleStateSetTester(Component component, AccessibleStateSet stateSet) { + this.component = Objects.requireNonNull(component, "component must not be null"); + this.stateSet = Objects.requireNonNull(stateSet, "stateSet must not be null"); + } + + /** + * Runs all generic state validations plus component-specific hooks. + */ + public void testAll() { + testActive(); + testArmed(); + testBusy(); + testChecked(); + testCollapsed(); + testEditable(); + testEnabled(); + testExpandable(); + testExpanded(); + testFocusable(); + testFocused(); + testHorizontal(); + testIconified(); + testModal(); + testMultiLine(); + testMultiSelectable(); + testOpaque(); + testPressed(); + testResizable(); + testSelectable(); + testSelected(); + testShowing(); + testSingleLine(); + testTransient(); + testVertical(); + testVisible(); + } + + public void testEnabled() { + assertStateMatches( + AccessibleState.ENABLED, + component.isEnabled(), + "component is enabled", + "component is not enabled" + ); + } + + public void testFocusable() { + assertStateMatches( + AccessibleState.FOCUSABLE, + component.isFocusable(), + "component is focusable", + "component is not focusable" + ); + } + + public void testFocused() { + boolean focused = isFocused(); + + if (stateSet.contains(AccessibleState.FOCUSED)) { + if (!stateSet.contains(AccessibleState.FOCUSABLE)) { + throw new RuntimeException( + "AccessibleStateSet contains FOCUSED but not FOCUSABLE" + ); + } + if (!focused) { + throw new RuntimeException( + "AccessibleStateSet contains FOCUSED but the component does not have focus" + ); + } + } else if (focused) { + throw new RuntimeException( + "AccessibleStateSet does not contain FOCUSED but the component has focus" + ); + } + } + + public void testShowing() { + assertStateMatches( + AccessibleState.SHOWING, + component.isShowing(), + "component is showing", + "component is not showing" + ); + } + + public void testVisible() { + assertStateMatches( + AccessibleState.VISIBLE, + component.isVisible(), + "component is visible", + "component is not visible" + ); + } + + public void testSelectable() { + AccessibleState selectionStatus = getSelectionStatus(); + + if (stateSet.contains(AccessibleState.SELECTABLE)) { + if (selectionStatus != AccessibleState.SELECTABLE + && selectionStatus != AccessibleState.SELECTED) { + throw new RuntimeException( + "AccessibleStateSet contains SELECTABLE but the component is not selectable" + ); + } + } else if (selectionStatus == AccessibleState.SELECTABLE) { + throw new RuntimeException( + "AccessibleStateSet does not contain SELECTABLE but the component is selectable" + ); + } + } + + public void testSelected() { + AccessibleState selectionStatus = getSelectionStatus(); + + if (stateSet.contains(AccessibleState.SELECTED)) { + if (!stateSet.contains(AccessibleState.SELECTABLE)) { + throw new RuntimeException( + "AccessibleStateSet contains SELECTED but not SELECTABLE" + ); + } + if (selectionStatus != AccessibleState.SELECTED) { + throw new RuntimeException( + "AccessibleStateSet contains SELECTED but the component is not selected" + ); + } + } else if (selectionStatus == AccessibleState.SELECTED) { + throw new RuntimeException( + "AccessibleStateSet does not contain SELECTED but the component is selected" + ); + } + } + + public void testOpaque() { + if (!(component instanceof JComponent jComponent)) { + return; + } + + assertStateMatches( + AccessibleState.OPAQUE, + jComponent.isOpaque(), + "component is opaque", + "component is not opaque" + ); + } + + /** + * Returns true if the component currently has focus. + */ + public boolean isFocused() { + return component.hasFocus(); + } + + /** + * Determines whether the component is selectable or selected. + * + * @return {@link AccessibleState#SELECTED} if selected, + * {@link AccessibleState#SELECTABLE} if selectable but not selected, + * or {@code null} if neither applies + */ + public AccessibleState getSelectionStatus() { + if (!(component instanceof Accessible accessible)) { + return null; + } + + AccessibleContext context = accessible.getAccessibleContext(); + if (context == null) { + return null; + } + + Accessible parent = context.getAccessibleParent(); + if (parent == null) { + return null; + } + + AccessibleContext parentContext = parent.getAccessibleContext(); + if (parentContext == null) { + return null; + } + + AccessibleSelection selection = parentContext.getAccessibleSelection(); + if (selection == null) { + return null; + } + + int index = context.getAccessibleIndexInParent(); + if (index < 0) { + return AccessibleState.SELECTABLE; + } + + return selection.isAccessibleChildSelected(index) + ? AccessibleState.SELECTED + : AccessibleState.SELECTABLE; + } + + private void assertStateMatches( + AccessibleState state, + boolean actualCondition, + String presentMessage, + String absentMessage) { + + boolean presentInStateSet = stateSet.contains(state); + + if (presentInStateSet && !actualCondition) { + throw new RuntimeException( + "AccessibleStateSet contains " + state + " but " + absentMessage + ); + } + + if (!presentInStateSet && actualCondition) { + throw new RuntimeException( + "AccessibleStateSet does not contain " + state + " but " + presentMessage + ); + } + } + + // Component-specific hooks (intentionally empty by default) + + public void testActive() { + } + + public void testArmed() { + } + + public void testBusy() { + } + + public void testChecked() { + } + + public void testCollapsed() { + } + + public void testEditable() { + } + + public void testExpandable() { + } + + public void testExpanded() { + } + + public void testHorizontal() { + } + + public void testIconified() { + } + + public void testModal() { + } + + public void testMultiLine() { + } + + public void testMultiSelectable() { + } + + public void testPressed() { + } + + public void testResizable() { + } + + public void testSingleLine() { + } + + public void testTransient() { + } + + public void testVertical() { + } +} diff --git a/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java new file mode 100644 index 0000000000000..2410cff997a78 --- /dev/null +++ b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java @@ -0,0 +1,334 @@ +/* + * 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.Button; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Scrollbar; +import java.util.Locale; +import java.util.Objects; + +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.accessibility.AccessibleValue; + +public final class AccessibleTestUtils { + + private AccessibleTestUtils() { + } + + public static void verifyAccessibleContextCommon( + AccessibleContext context, + String expectedName, + String expectedDescription, + AccessibleRole expectedRole, + boolean expectAction, + boolean expectSelection, + boolean expectText, + boolean expectValue) { + + Objects.requireNonNull(context, "AccessibleContext must not be null"); + + assertExpectedString( + "getAccessibleName", + expectedName, + context.getAccessibleName() + ); + + assertExpectedString( + "getAccessibleDescription", + expectedDescription, + context.getAccessibleDescription() + ); + + if (expectedRole != null) { + AccessibleRole actualRole = context.getAccessibleRole(); + if (actualRole == null) { + throw new RuntimeException("getAccessibleRole returned null"); + } + if (!expectedRole.equals(actualRole)) { + throw new RuntimeException(String.format( + "getAccessibleRole returned [%s]; expected [%s]", + actualRole, expectedRole + )); + } + } + + AccessibleStateSet stateSet = context.getAccessibleStateSet(); + if (stateSet == null) { + throw new RuntimeException("getAccessibleStateSet returned null"); + } + + assertPresence("getAccessibleAction", expectAction, context.getAccessibleAction()); + assertPresence("getAccessibleSelection", expectSelection, context.getAccessibleSelection()); + assertPresence("getAccessibleText", expectText, context.getAccessibleText()); + assertPresence("getAccessibleValue", expectValue, context.getAccessibleValue()); + } + + public static void verifyAWTComponentAccessibility( + Component component, + String expectedName, + String expectedDescription, + AccessibleRole expectedRole, + boolean expectAction, + boolean expectSelection, + boolean expectText, + boolean expectValue) { + + Objects.requireNonNull(component, "Component under test must not be null"); + + AccessibleContext context = component.getAccessibleContext(); + verifyAccessibleContextCommon( + context, + expectedName, + expectedDescription, + expectedRole, + expectAction, + expectSelection, + expectText, + expectValue + ); + + assertLocaleMatches(component, context); + + AccessibleComponent accessibleComponent = context.getAccessibleComponent(); + if (accessibleComponent == null) { + throw new RuntimeException("getAccessibleComponent returned null"); + } + + new AccessibleComponentTester(component, accessibleComponent).test(); + } + + public static void verifyChoiceAccessibility( + Choice choice, + String expectedName, + String expectedDescription) { + + Objects.requireNonNull(choice, "Choice must not be null"); + + verifyAWTComponentAccessibility( + choice, + expectedName, + expectedDescription, + AccessibleRole.COMBO_BOX, + true, + false, + false, + false + ); + + AccessibleContext context = choice.getAccessibleContext(); + + AccessibleAction action = context.getAccessibleAction(); + if (action == null) { + throw new RuntimeException("getAccessibleAction should not return null for Choice"); + } + + AccessibleValue value = context.getAccessibleValue(); + if (value != null) { + throw new RuntimeException("getAccessibleValue should return null for Choice"); + } + } + + public static void verifyScrollbarAccessibility( + Scrollbar scrollbar, + String expectedName, + String expectedDescription) { + + Objects.requireNonNull(scrollbar, "Scrollbar must not be null"); + + verifyAWTComponentAccessibility( + scrollbar, + expectedName, + expectedDescription, + AccessibleRole.SCROLL_BAR, + false, + false, + false, + true + ); + + AccessibleValue value = scrollbar.getAccessibleContext().getAccessibleValue(); + if (value == null) { + throw new RuntimeException("getAccessibleValue should not return null for Scrollbar"); + } + + assertIntValueEquals( + "getCurrentAccessibleValue", + scrollbar.getValue(), + value.getCurrentAccessibleValue() + ); + + assertIntValueEquals( + "getMinimumAccessibleValue", + scrollbar.getMinimum(), + value.getMinimumAccessibleValue() + ); + + assertIntValueEquals( + "getMaximumAccessibleValue", + scrollbar.getMaximum(), + value.getMaximumAccessibleValue() + ); + + if (!value.setCurrentAccessibleValue(Integer.valueOf(5))) { + throw new RuntimeException("setCurrentAccessibleValue(5) returned false for Scrollbar"); + } + + assertIntValueEquals( + "getCurrentAccessibleValue after setCurrentAccessibleValue(5)", + 5, + value.getCurrentAccessibleValue() + ); + + if (scrollbar.getValue() != 5) { + throw new RuntimeException( + "setCurrentAccessibleValue(5) did not update Scrollbar.getValue(); actual value: " + + scrollbar.getValue() + ); + } + } + + public static void verifyButtonAccessibility( + Button button, + String expectedName, + String expectedDescription) { + + Objects.requireNonNull(button, "Button must not be null"); + + verifyAWTComponentAccessibility( + button, + expectedName, + expectedDescription, + AccessibleRole.PUSH_BUTTON, + true, + false, + false, + true + ); + + AccessibleContext context = button.getAccessibleContext(); + + AccessibleAction action = context.getAccessibleAction(); + if (action == null) { + throw new RuntimeException("getAccessibleAction should not return null for Button"); + } + + int actionCount = action.getAccessibleActionCount(); + if (actionCount != 1) { + throw new RuntimeException( + "getAccessibleActionCount should return 1 for Button; got " + actionCount + ); + } + + String actionDescription = action.getAccessibleActionDescription(0); + if (!"click".equals(actionDescription)) { + throw new RuntimeException( + "getAccessibleActionDescription(0) should return \"click\" for Button; got [" + + actionDescription + "]" + ); + } + + AccessibleValue value = context.getAccessibleValue(); + if (value == null) { + throw new RuntimeException("getAccessibleValue should not return null for Button"); + } + + assertIntValueEquals("getCurrentAccessibleValue", 0, value.getCurrentAccessibleValue()); + assertIntValueEquals("getMinimumAccessibleValue", 0, value.getMinimumAccessibleValue()); + assertIntValueEquals("getMaximumAccessibleValue", 0, value.getMaximumAccessibleValue()); + + if (value.setCurrentAccessibleValue(Integer.valueOf(5))) { + throw new RuntimeException( + "setCurrentAccessibleValue(5) should return false for Button" + ); + } + + assertIntValueEquals( + "getCurrentAccessibleValue after setCurrentAccessibleValue(5)", + 0, + value.getCurrentAccessibleValue() + ); + } + + private static void assertExpectedString(String methodName, String expected, String actual) { + if (expected == null) { + throw new RuntimeException("Excepted value is null. Provide " + + "excepted value"); + } + + if (actual == null) { + throw new RuntimeException(methodName + " returned null; expected" + + " [" + expected + "]"); + } + if (!expected.equals(actual)) { + throw new RuntimeException(methodName + " returned [" + actual + + "]; expected [" + expected + "]"); + } + } + + private static void assertPresence(String methodName, boolean expectedPresent, Object value) { + if (expectedPresent && value == null) { + throw new RuntimeException(methodName + " returned null but was expected"); + } + if (!expectedPresent && value != null) { + throw new RuntimeException(methodName + " returned non-null but " + + "was expected to be null"); + } + } + + private static void assertLocaleMatches(Component component, AccessibleContext context) { + Locale componentLocale = component.getLocale(); + Locale accessibleLocale = context.getLocale(); + + if (componentLocale == null) { + throw new RuntimeException("Component.getLocale returned null"); + } + if (accessibleLocale == null) { + throw new RuntimeException("AccessibleContext.getLocale returned null"); + } + if (!componentLocale.equals(accessibleLocale)) { + throw new RuntimeException(String.format( + "AccessibleContext.getLocale returned [%s], but Component" + + ".getLocale returned [%s]", + accessibleLocale, componentLocale + )); + } + } + + private static void assertIntValueEquals(String methodName, int expected, Number actual) { + if (actual == null) { + throw new RuntimeException(methodName + " returned null; expected [" + expected + "]"); + } + if (actual.intValue() != expected) { + throw new RuntimeException( + methodName + " returned [" + actual + "]; expected [" + expected + "]" + ); + } + } +} diff --git a/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java b/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java index 52174ab2f5546..2cbbf5f653422 100644 --- a/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java +++ b/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java @@ -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 @@ -22,8 +22,9 @@ */ /* - * @test + * @test id=default * @bug 8270290 + * @requires os.family != "windows" * @library /test/lib * @run main/othervm NTLMHeadTest SERVER * @run main/othervm NTLMHeadTest PROXY @@ -48,6 +49,17 @@ * include the body. */ +/* + * @test id=windows + * @bug 8270290 + * @comment Only run on specific Windows OS versions because NTLMv1 is no longer supported starting Windows 11 and Windows Server 2025 + * @requires os.family == "windows" & (os.name == "Windows 10" | os.name == "Windows Server 2016" | os.name == "Windows Server 2019" | os.name == "Windows Server 2022") + * @library /test/lib + * @run main/othervm NTLMHeadTest SERVER + * @run main/othervm NTLMHeadTest PROXY + * @run main/othervm NTLMHeadTest TUNNEL + */ + import java.net.*; import java.io.*; import java.util.*; diff --git a/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java b/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java index 1c2262ba8e2e6..7a8082a40129b 100644 --- a/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java +++ b/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java @@ -26,7 +26,8 @@ * @bug 8225425 * @summary Verifies that transparent NTLM (on Windows) is not used by default, * and is used only when the relevant property is set. - * @requires os.family == "windows" + * @comment Only run on specific Windows OS versions because NTLMv1 is no longer supported starting Windows 11 and Windows Server 2025 + * @requires os.family == "windows" & (os.name == "Windows 10" | os.name == "Windows Server 2016" | os.name == "Windows Server 2019" | os.name == "Windows Server 2022") * @library /test/lib * @run junit/othervm * -Dtest.auth.succeed=false