diff --git a/bin/blessed-modifier-order.sh b/bin/blessed-modifier-order.sh index 4e999e02506..548a89dbe14 100644 --- a/bin/blessed-modifier-order.sh +++ b/bin/blessed-modifier-order.sh @@ -1,5 +1,6 @@ #!/bin/bash # +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. # Copyright 2015 Google, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # @@ -26,12 +27,17 @@ usage() { echo "$0 DIR ..." echo "Modifies in place all the java source files found" echo "in the given directories so that all java language modifiers" - echo "are in the canonical order given by Modifier#toString()." + echo "are in the canonical order." echo "Tries to get it right even within javadoc comments," echo "and even if the list of modifiers spans 2 lines." echo echo "See:" - echo "https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Modifier.html#toString-int-" + echo "https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.1.1" + echo "https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.3.1" + echo "https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.4.3" + echo "https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.8.3" + echo "https://docs.oracle.com/javase/specs/jls/se21/html/jls-9.html#jls-9.1.1" + echo "https://docs.oracle.com/javase/specs/jls/se21/html/jls-9.html#jls-9.4" echo echo "Example:" echo "$0 jdk/src/java.base jdk/test/java/{util,io,lang}" @@ -46,7 +52,7 @@ for dir in "${dirs[@]}"; do [[ -d "$dir" ]] || usage; done declare -ar modifiers=( public protected private - abstract static final transient + abstract default static final sealed non-sealed transient volatile synchronized native strictfp ) declare -r SAVE_IFS="$IFS" diff --git a/doc/building.html b/doc/building.html index 3aad6eae074..69fb371a477 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1499,9 +1499,7 @@

Using Debian debootstrap

--resolve-deps \ buster \ ~/sysroot-arm64 \ - https://httpredir.debian.org/debian/ -

If the target architecture is riscv64, the path should -be debian-ports instead of debian.

+ https://httpredir.debian.org/debian/
  • To create an Ubuntu-based chroot:

    sudo debootstrap \
       --arch=arm64 \
    diff --git a/doc/building.md b/doc/building.md
    index 611cfe15915..abbd935f652 100644
    --- a/doc/building.md
    +++ b/doc/building.md
    @@ -1316,9 +1316,6 @@ For example, cross-compiling to AArch64 from x86_64 could be done like this:
         https://httpredir.debian.org/debian/
       ```
     
    -  If the target architecture is `riscv64`, the path should be `debian-ports`
    -  instead of `debian`.
    -
     * To create an Ubuntu-based chroot:
     
       ```
    diff --git a/make/CompileDemos.gmk b/make/CompileDemos.gmk
    index 4d8a9598da7..dfe30c70173 100644
    --- a/make/CompileDemos.gmk
    +++ b/make/CompileDemos.gmk
    @@ -58,7 +58,7 @@ DEMO_MANIFEST := $(SUPPORT_OUTPUTDIR)/demos/java-main-manifest.mf
     # This rule will be depended on due to the MANIFEST line in SetupBuildDemo
     # and SetupBuildJvmtiDemo.
     $(eval $(call SetupTextFileProcessing, BUILD_JAVA_MANIFEST, \
    -  SOURCE_FILES := $(TOPDIR)/make/data/mainmanifest/manifest.mf, \
    +  SOURCE_FILES := $(TOPDIR)/make/data/mainmanifest/manifest.mf.template, \
       OUTPUT_FILE := $(DEMO_MANIFEST), \
       REPLACEMENTS := \
           @@VERSION_SPECIFICATION@@ => $(VERSION_SPECIFICATION) ; \
    diff --git a/make/JrtfsJar.gmk b/make/JrtfsJar.gmk
    index 50ae82ca565..b0b7ed6ce08 100644
    --- a/make/JrtfsJar.gmk
    +++ b/make/JrtfsJar.gmk
    @@ -33,7 +33,7 @@ include TextFileProcessing.gmk
     
     # This rule will be depended on due to the MANIFEST line
     $(eval $(call SetupTextFileProcessing, BUILD_JAVA_MANIFEST, \
    -  SOURCE_FILES := $(TOPDIR)/make/data/mainmanifest/manifest.mf, \
    +  SOURCE_FILES := $(TOPDIR)/make/data/mainmanifest/manifest.mf.template, \
       OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf, \
       REPLACEMENTS := \
           @@VERSION_SPECIFICATION@@ => $(VERSION_SPECIFICATION) ; \
    diff --git a/make/MacBundles.gmk b/make/MacBundles.gmk
    index c1c51570a1d..39da6c9cdb3 100644
    --- a/make/MacBundles.gmk
    +++ b/make/MacBundles.gmk
    @@ -69,7 +69,7 @@ ifeq ($(call isTargetOs, macosx), true)
       ))
     
       $(eval $(call SetupTextFileProcessing, BUILD_JDK_PLIST, \
    -      SOURCE_FILES := $(MACOSX_PLIST_SRC)/JDK-Info.plist, \
    +      SOURCE_FILES := $(MACOSX_PLIST_SRC)/JDK-Info.plist.template, \
           OUTPUT_FILE := $(JDK_MACOSX_CONTENTS_DIR)/Info.plist, \
           REPLACEMENTS := \
               @@ID@@ => $(MACOSX_BUNDLE_ID_BASE).jdk ; \
    @@ -82,7 +82,7 @@ ifeq ($(call isTargetOs, macosx), true)
       ))
     
       $(eval $(call SetupTextFileProcessing, BUILD_JRE_PLIST, \
    -      SOURCE_FILES := $(MACOSX_PLIST_SRC)/JRE-Info.plist, \
    +      SOURCE_FILES := $(MACOSX_PLIST_SRC)/JRE-Info.plist.template, \
           OUTPUT_FILE := $(JRE_MACOSX_CONTENTS_DIR)/Info.plist, \
           REPLACEMENTS := \
               @@ID@@ => $(MACOSX_BUNDLE_ID_BASE).jre ; \
    diff --git a/make/Main.gmk b/make/Main.gmk
    index a50d3c50278..0014c97cc0b 100644
    --- a/make/Main.gmk
    +++ b/make/Main.gmk
    @@ -744,9 +744,16 @@ endif
     
     $(eval $(call SetupTarget, build-test-lib, \
         MAKEFILE := test/BuildTestLib, \
    +    TARGET := build-test-lib, \
         DEPS := exploded-image, \
     ))
     
    +$(eval $(call SetupTarget, test-image-lib, \
    +    MAKEFILE := test/BuildTestLib, \
    +    TARGET := test-image-lib, \
    +    DEPS := build-test-lib, \
    +))
    +
     ifeq ($(BUILD_FAILURE_HANDLER), true)
       # Builds the failure handler jtreg extension
       $(eval $(call SetupTarget, build-test-failure-handler, \
    @@ -781,7 +788,7 @@ endif
     
     $(eval $(call SetupTarget, build-microbenchmark, \
         MAKEFILE := test/BuildMicrobenchmark, \
    -    DEPS := interim-langtools exploded-image, \
    +    DEPS := interim-langtools exploded-image build-test-lib, \
     ))
     
     ################################################################################
    @@ -1264,7 +1271,7 @@ all-docs-bundles: docs-jdk-bundles docs-javase-bundles docs-reference-bundles
     # This target builds the test image
     test-image: prepare-test-image test-image-jdk-jtreg-native \
         test-image-demos-jdk test-image-libtest-jtreg-native \
    -    test-image-lib-native
    +    test-image-lib test-image-lib-native
     
     ifneq ($(JVM_TEST_IMAGE_TARGETS), )
       # If JVM_TEST_IMAGE_TARGETS is externally defined, use it instead of the
    diff --git a/make/autoconf/Makefile.in b/make/autoconf/Makefile.template
    similarity index 100%
    rename from make/autoconf/Makefile.in
    rename to make/autoconf/Makefile.template
    diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4
    index af963359583..5a1fbc07952 100644
    --- a/make/autoconf/basic.m4
    +++ b/make/autoconf/basic.m4
    @@ -448,17 +448,17 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR],
       AC_SUBST(CONFIGURESUPPORT_OUTPUTDIR)
     
       # The spec.gmk file contains all variables for the make system.
    -  AC_CONFIG_FILES([$OUTPUTDIR/spec.gmk:$AUTOCONF_DIR/spec.gmk.in])
    +  AC_CONFIG_FILES([$OUTPUTDIR/spec.gmk:$AUTOCONF_DIR/spec.gmk.template])
       # The bootcycle-spec.gmk file contains support for boot cycle builds.
    -  AC_CONFIG_FILES([$OUTPUTDIR/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in])
    +  AC_CONFIG_FILES([$OUTPUTDIR/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.template])
       # The buildjdk-spec.gmk file contains support for building a buildjdk when cross compiling.
    -  AC_CONFIG_FILES([$OUTPUTDIR/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in])
    +  AC_CONFIG_FILES([$OUTPUTDIR/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.template])
       # The compare.sh is used to compare the build output to other builds.
    -  AC_CONFIG_FILES([$OUTPUTDIR/compare.sh:$AUTOCONF_DIR/compare.sh.in])
    +  AC_CONFIG_FILES([$OUTPUTDIR/compare.sh:$AUTOCONF_DIR/compare.sh.template])
       # The generated Makefile knows where the spec.gmk is and where the source is.
       # You can run make from the OUTPUTDIR, or from the top-level Makefile
       # which will look for generated configurations
    -  AC_CONFIG_FILES([$OUTPUTDIR/Makefile:$AUTOCONF_DIR/Makefile.in])
    +  AC_CONFIG_FILES([$OUTPUTDIR/Makefile:$AUTOCONF_DIR/Makefile.template])
     ])
     
     ###############################################################################
    diff --git a/make/autoconf/bootcycle-spec.gmk.in b/make/autoconf/bootcycle-spec.gmk.template
    similarity index 100%
    rename from make/autoconf/bootcycle-spec.gmk.in
    rename to make/autoconf/bootcycle-spec.gmk.template
    diff --git a/make/autoconf/buildjdk-spec.gmk.in b/make/autoconf/buildjdk-spec.gmk.template
    similarity index 100%
    rename from make/autoconf/buildjdk-spec.gmk.in
    rename to make/autoconf/buildjdk-spec.gmk.template
    diff --git a/make/autoconf/compare.sh.in b/make/autoconf/compare.sh.template
    similarity index 100%
    rename from make/autoconf/compare.sh.in
    rename to make/autoconf/compare.sh.template
    diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4
    index 6a7662556fd..7c9ecad7779 100644
    --- a/make/autoconf/jdk-version.m4
    +++ b/make/autoconf/jdk-version.m4
    @@ -110,6 +110,15 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
         CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
       AC_SUBST(COMPANY_NAME)
     
    +  # Set the JDK RC Company name
    +  # Otherwise uses the value set for "vendor-name".
    +  UTIL_ARG_WITH(NAME: jdk-rc-company-name, TYPE: string,
    +    DEFAULT: $COMPANY_NAME,
    +    DESC: [Set JDK RC company name. This is used for CompanyName properties of MS Windows binaries.],
    +    DEFAULT_DESC: [from branding.conf],
    +    CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
    +  AC_SUBST(JDK_RC_COMPANY_NAME)
    +
       # The vendor URL, if any
       # Only set VENDOR_URL if '--with-vendor-url' was used and is not empty.
       # Otherwise we will use the value from "branding.conf" included above.
    diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.template
    similarity index 99%
    rename from make/autoconf/spec.gmk.in
    rename to make/autoconf/spec.gmk.template
    index 8a1eb8ed27f..b78d3da6b32 100644
    --- a/make/autoconf/spec.gmk.in
    +++ b/make/autoconf/spec.gmk.template
    @@ -191,6 +191,7 @@ PRODUCT_NAME := @PRODUCT_NAME@
     PRODUCT_SUFFIX := @PRODUCT_SUFFIX@
     JDK_RC_PLATFORM_NAME := @JDK_RC_PLATFORM_NAME@
     JDK_RC_NAME := @JDK_RC_NAME@
    +JDK_RC_COMPANY_NAME := @JDK_RC_COMPANY_NAME@
     COMPANY_NAME := @COMPANY_NAME@
     HOTSPOT_VM_DISTRO := @HOTSPOT_VM_DISTRO@
     MACOSX_BUNDLE_NAME_BASE := @MACOSX_BUNDLE_NAME_BASE@
    diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk
    index 6a963ac2c49..1a1333cf517 100644
    --- a/make/common/JdkNativeCompilation.gmk
    +++ b/make/common/JdkNativeCompilation.gmk
    @@ -98,7 +98,7 @@ GLOBAL_VERSION_INFO_RESOURCE := $(TOPDIR)/src/java.base/windows/native/common/ve
     
     JDK_RCFLAGS=$(RCFLAGS) \
         -D"JDK_VERSION_STRING=$(VERSION_STRING)" \
    -    -D"JDK_COMPANY=$(COMPANY_NAME)" \
    +    -D"JDK_COMPANY=$(JDK_RC_COMPANY_NAME)" \
         -D"JDK_VER=$(VERSION_NUMBER_FOUR_POSITIONS)" \
         -D"JDK_COPYRIGHT=Copyright \xA9 $(COPYRIGHT_YEAR)" \
         -D"JDK_NAME=$(JDK_RC_NAME) $(VERSION_SHORT)" \
    diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk
    index 21d2b9a9300..8041e9fe681 100644
    --- a/make/common/modules/LauncherCommon.gmk
    +++ b/make/common/modules/LauncherCommon.gmk
    @@ -112,7 +112,7 @@ define SetupBuildLauncherBody
         $1_PLIST_FILE := $$(SUPPORT_OUTPUTDIR)/native/$$(MODULE)/$1/Info.plist
     
         $$(eval $$(call SetupTextFileProcessing, BUILD_PLIST_$1, \
    -        SOURCE_FILES := $(TOPDIR)/make/data/bundle/cmdline-Info.plist, \
    +        SOURCE_FILES := $(TOPDIR)/make/data/bundle/cmdline-Info.plist.template, \
             OUTPUT_FILE := $$($1_PLIST_FILE), \
             REPLACEMENTS := \
                 @@ID@@ => $(MACOSX_BUNDLE_ID_BASE).$1 ; \
    diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
    index d497f5d82d3..3bef7eb025f 100644
    --- a/make/conf/jib-profiles.js
    +++ b/make/conf/jib-profiles.js
    @@ -1206,7 +1206,7 @@ var getJibProfilesDependencies = function (input, common) {
     
             jcov: {
                 organization: common.organization,
    -            revision: "3.0-15-jdk-asm+1.0",
    +            revision: "3.0-16-jdk-asm+1.0",
                 ext: "zip",
                 environment_name: "JCOV_HOME",
             },
    diff --git a/make/data/bundle/JDK-Info.plist b/make/data/bundle/JDK-Info.plist.template
    similarity index 100%
    rename from make/data/bundle/JDK-Info.plist
    rename to make/data/bundle/JDK-Info.plist.template
    diff --git a/make/data/bundle/JRE-Info.plist b/make/data/bundle/JRE-Info.plist.template
    similarity index 100%
    rename from make/data/bundle/JRE-Info.plist
    rename to make/data/bundle/JRE-Info.plist.template
    diff --git a/make/data/bundle/cmdline-Info.plist b/make/data/bundle/cmdline-Info.plist.template
    similarity index 100%
    rename from make/data/bundle/cmdline-Info.plist
    rename to make/data/bundle/cmdline-Info.plist.template
    diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix
    index b0c868d0451..bdc10add4f2 100644
    --- a/make/data/hotspot-symbols/symbols-unix
    +++ b/make/data/hotspot-symbols/symbols-unix
    @@ -228,6 +228,7 @@ JVM_VirtualThreadEnd
     JVM_VirtualThreadMount
     JVM_VirtualThreadUnmount
     JVM_VirtualThreadHideFrames
    +JVM_VirtualThreadDisableSuspend
     
     # Scoped values
     JVM_EnsureMaterializedForStackWalk_func
    diff --git a/make/data/mainmanifest/manifest.mf b/make/data/mainmanifest/manifest.mf.template
    similarity index 100%
    rename from make/data/mainmanifest/manifest.mf
    rename to make/data/mainmanifest/manifest.mf.template
    diff --git a/make/hotspot/gensrc/GenerateSources.gmk b/make/hotspot/gensrc/GenerateSources.gmk
    index 9b42493f628..c92408b7d54 100644
    --- a/make/hotspot/gensrc/GenerateSources.gmk
    +++ b/make/hotspot/gensrc/GenerateSources.gmk
    @@ -48,7 +48,7 @@ $(eval $(call IncludeCustomExtension, hotspot/gensrc/GenerateSources.gmk))
     
     # Setup the hotspot launcher script for developer use
     $(eval $(call SetupTextFileProcessing, CREATE_HOTSPOT_LAUNCHER, \
    -    SOURCE_FILES := $(TOPDIR)/make/scripts/hotspot.sh, \
    +    SOURCE_FILES := $(TOPDIR)/make/scripts/hotspot.sh.template, \
         OUTPUT_FILE := $(JVM_OUTPUTDIR)/hotspot, \
         REPLACEMENTS := \
             @@LIBARCH@@ => $(OPENJDK_TARGET_CPU_LEGACY_LIB) ; \
    diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
    index b6298c00c9a..442a245f92f 100644
    --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
    +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1289,25 +1289,58 @@ private static Map coverageLevelsMap() throws Exception {
          */
         private static void generateTZDBShortNamesMap() throws IOException {
             Files.walk(Path.of(tzDataDir), 1, FileVisitOption.FOLLOW_LINKS)
    -            .filter(p -> p.toFile().isFile())
    +            .filter(p -> p.toFile().isFile() && !p.endsWith("jdk11_backward"))
                 .forEach(p -> {
                     try {
                         String zone = null;
                         String rule = null;
                         String format = null;
    +                    boolean inVanguard = false;
    +                    boolean inRearguard = false;
                         for (var line : Files.readAllLines(p)) {
    -                        if (line.contains("#STDOFF")) continue;
    +                        // Interpret the line in rearguard mode so that STD/DST
    +                        // correctly handles negative DST cases, such as "GMT/IST"
    +                        // vs. "IST/GMT" case for Europe/Dublin
    +                        if (inVanguard) {
    +                            if (line.startsWith("# Rearguard")) {
    +                                inVanguard = false;
    +                                inRearguard = true;
    +                            }
    +                            continue;
    +                        } else if (line.startsWith("# Vanguard")) {
    +                            inVanguard = true;
    +                            continue;
    +                        }
    +                        if (inRearguard) {
    +                            if (line.startsWith("# End of rearguard")) {
    +                                inRearguard = false;
    +                                continue;
    +                            } else {
    +                                if (line.startsWith("#\t")) {
    +                                    line = line.substring(1); // omit #
    +                                }
    +                            }
    +                        }
    +                        if (line.isBlank() || line.matches("^[ \t]*#.*")) {
    +                            // ignore blank/comment lines
    +                            continue;
    +                        }
    +                        // remove comments in-line
                             line = line.replaceAll("[ \t]*#.*", "");
     
                             // Zone line
                             if (line.startsWith("Zone")) {
    +                            if (zone != null) {
    +                                tzdbShortNamesMap.put(zone, format + NBSP + rule);
    +                            }
                                 var zl = line.split("[ \t]+", -1);
                                 zone = zl[1];
                                 rule = zl[3];
                                 format = zl[4];
                             } else {
                                 if (zone != null) {
    -                                if (line.isBlank()) {
    +                                if (line.startsWith("Rule") ||
    +                                    line.startsWith("Link")) {
                                         tzdbShortNamesMap.put(zone, format + NBSP + rule);
                                         zone = null;
                                         rule = null;
    diff --git a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java
    index 561edbef034..9655e08016c 100644
    --- a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java
    +++ b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -32,6 +32,7 @@
     import java.io.FileOutputStream;
     import java.io.InputStream;
     import java.text.SimpleDateFormat;
    +import java.util.Arrays;
     import java.util.Date;
     import java.util.HashMap;
     import java.util.Locale;
    @@ -339,9 +340,15 @@ private static void buildOtherTables() {
                     validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6));
                 checkCurrencyCode(currencyCode);
                 int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')];
    -            if (tableEntry == INVALID_COUNTRY_ENTRY ||
    -                    (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 ||
    -                    (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) {
    +
    +            // Do not allow a future currency to be classified as an otherCurrency,
    +            // otherwise it will leak out into Currency:getAvailableCurrencies
    +            boolean futureCurrency = Arrays.asList(specialCaseNewCurrencies).contains(currencyCode);
    +            boolean simpleCurrency = (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) == (currencyCode.charAt(2) - 'A');
    +
    +            // If neither a simple currency, or one defined in the future
    +            // then the current currency is applicable to be added to the otherTable
    +            if (!futureCurrency && !simpleCurrency) {
                     if (otherCurrenciesCount == maxOtherCurrencies) {
                         throw new RuntimeException("too many other currencies");
                     }
    diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk
    index 30261bab6e1..924cb8aae26 100644
    --- a/make/modules/java.base/Lib.gmk
    +++ b/make/modules/java.base/Lib.gmk
    @@ -245,7 +245,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, x86_64)+$(INCLUDE_COMPILER2)
           TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
           OPTIMIZATION := HIGH, \
           CFLAGS := $(CFLAGS_JDKLIB), \
    -      CXXFLAGS := $(CXXFLAGS_JDKLIB), \
    +      CXXFLAGS := $(CXXFLAGS_JDKLIB) -std=c++17, \
           LDFLAGS := $(LDFLAGS_JDKLIB) \
               $(call SET_SHARED_LIBRARY_ORIGIN), \
           LIBS := $(LIBCXX), \
    diff --git a/make/modules/java.instrument/Lib.gmk b/make/modules/java.instrument/Lib.gmk
    index ae985b3158f..94246226644 100644
    --- a/make/modules/java.instrument/Lib.gmk
    +++ b/make/modules/java.instrument/Lib.gmk
    @@ -1,5 +1,5 @@
     #
    -# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
    +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
     # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     #
     # This code is free software; you can redistribute it and/or modify it
    @@ -47,7 +47,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBINSTRUMENT, \
         LDFLAGS_macosx := -L$(call FindLibDirForModule, java.base), \
         LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
         LIBS := $(JDKLIB_LIBS), \
    -    LIBS_unix := -ljava -ljvm $(LIBZ_LIBS), \
    +    LIBS_unix := $(LIBZ_LIBS), \
         LIBS_linux := -ljli $(LIBDL), \
         LIBS_aix := -liconv -ljli_static $(LIBDL), \
         LIBS_macosx := -ljli -liconv -framework Cocoa -framework Security \
    diff --git a/make/scripts/hotspot.sh b/make/scripts/hotspot.sh.template
    similarity index 100%
    rename from make/scripts/hotspot.sh
    rename to make/scripts/hotspot.sh.template
    diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk
    index 1d4a9c63508..7a5a6f7f5b9 100644
    --- a/make/test/BuildMicrobenchmark.gmk
    +++ b/make/test/BuildMicrobenchmark.gmk
    @@ -53,11 +53,10 @@ JMH_UNPACKED_DIR := $(MICROBENCHMARK_OUTPUT)/jmh_jars
     JMH_UNPACKED_JARS_DONE := $(JMH_UNPACKED_DIR)/_unpacked.marker
     
     # External dependencies
    -JMH_COMPILE_JARS := $(JMH_CORE_JAR) $(JMH_GENERATOR_JAR)
    +WHITEBOX_JAR := $(SUPPORT_OUTPUTDIR)/test/lib/wb.jar
    +JMH_COMPILE_JARS := $(JMH_CORE_JAR) $(JMH_GENERATOR_JAR) $(WHITEBOX_JAR)
     JMH_RUNTIME_JARS := $(JMH_CORE_JAR) $(JMH_COMMONS_MATH_JAR) $(JMH_JOPT_SIMPLE_JAR)
     
    -MICROBENCHMARK_CLASSPATH := $(call PathList, $(JMH_COMPILE_JARS))
    -
     # Native dependencies
     MICROBENCHMARK_NATIVE_SRC_DIRS := $(MICROBENCHMARK_SRC)
     MICROBENCHMARK_NATIVE_OUTPUT := $(MICROBENCHMARK_OUTPUT)/native
    @@ -92,25 +91,28 @@ $(eval $(call SetupJavaCompilation, BUILD_INDIFY, \
     $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
         TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
         SMALL_JAVA := false, \
    -    CLASSPATH := $(MICROBENCHMARK_CLASSPATH), \
    -    DISABLED_WARNINGS := restricted this-escape processing rawtypes unchecked cast serial preview deprecation, \
    +    CLASSPATH := $(JMH_COMPILE_JARS), \
    +    DISABLED_WARNINGS := restricted this-escape processing rawtypes cast \
    +        serial preview unchecked deprecation, \
         SRC := $(MICROBENCHMARK_SRC), \
         BIN := $(MICROBENCHMARK_CLASSES), \
    -    JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \
    -        --add-exports java.base/sun.invoke.util=ALL-UNNAMED \
    +    JAVAC_FLAGS := \
             --add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
    +        --add-exports java.base/jdk.internal.event=ALL-UNNAMED \
    +        --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
    -        --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED \
    +        --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
    -        --add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
    -        --add-exports java.base/jdk.internal.event=ALL-UNNAMED \
    -        --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
    +        --add-exports java.base/sun.invoke.util=ALL-UNNAMED \
    +        --add-exports java.base/sun.security.util=ALL-UNNAMED \
             --enable-preview \
             -processor org.openjdk.jmh.generators.BenchmarkProcessor, \
    -    JAVA_FLAGS := --add-modules jdk.unsupported --limit-modules java.management \
    +    JAVA_FLAGS := \
             --add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
    -        --enable-preview, \
    +        --add-modules jdk.unsupported \
    +        --enable-preview \
    +        --limit-modules java.management, \
     ))
     
     $(BUILD_JDK_MICROBENCHMARK): $(JMH_COMPILE_JARS)
    diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk
    index 72f777ec6c1..4445e483ac2 100644
    --- a/make/test/BuildTestLib.gmk
    +++ b/make/test/BuildTestLib.gmk
    @@ -23,12 +23,22 @@
     # questions.
     #
     
    +################################################################################
    +# This file builds the Java components of testlib.
    +# It also covers the test-image part, where the built files are copied to the
    +# test image.
    +################################################################################
    +
     default: all
     
     include $(SPEC)
     include MakeBase.gmk
     include JavaCompilation.gmk
     
    +################################################################################
    +# Targets for building the test lib jars
    +################################################################################
    +
     TARGETS :=
     
     TEST_LIB_SOURCE_DIR := $(TOPDIR)/test/lib
    @@ -48,23 +58,42 @@ TARGETS += $(BUILD_WB_JAR)
     $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \
         TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
         SRC := $(TEST_LIB_SOURCE_DIR), \
    -    EXCLUDES := jdk/test/lib/containers jdk/test/lib/security, \
    +    EXCLUDES := jdk/test/lib/containers jdk/test/lib/security org, \
         BIN := $(TEST_LIB_SUPPORT)/test-lib_classes, \
         HEADERS := $(TEST_LIB_SUPPORT)/test-lib_headers, \
         JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \
    -    DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview, \
    +    DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview varargs, \
         JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED \
             --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
    +        --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
    +        --add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
    +        --add-exports jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
    +        --add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
    +        --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
    +        --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
             --enable-preview, \
     ))
     
     TARGETS += $(BUILD_TEST_LIB_JAR)
     
    -##########################################################################################
    +build-test-lib: $(TARGETS)
    +
    +################################################################################
    +# Targets for building test-image.
    +################################################################################
    +
    +# Copy the jars to the test image.
    +$(eval $(call SetupCopyFiles, COPY_LIBTEST_JARS, \
    +    DEST := $(TEST_IMAGE_DIR)/lib-test, \
    +    FILES := $(BUILD_WB_JAR_JAR) $(BUILD_TEST_LIB_JAR_JAR), \
    +))
    +#
    +
    +test-image-lib: $(COPY_LIBTEST_JARS)
     
    -all: $(TARGETS)
    +all: build-test-lib
     
    -.PHONY: default all
    +.PHONY: default all build-test-lib test-image-lib
    diff --git a/make/test/BuildTestLibNative.gmk b/make/test/BuildTestLibNative.gmk
    index 00c7607913b..455936d163f 100644
    --- a/make/test/BuildTestLibNative.gmk
    +++ b/make/test/BuildTestLibNative.gmk
    @@ -1,5 +1,5 @@
     #
    -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
    +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
     # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     #
     # This code is free software; you can redistribute it and/or modify it
    @@ -45,6 +45,10 @@ BUILD_LIBTEST_OUTPUT_DIR := $(OUTPUTDIR)/support/test/lib/native
     
     BUILD_LIBTEST_IMAGE_DIR := $(TEST_IMAGE_DIR)/lib
     
    +ifeq ($(call isTargetOs, windows), false)
    +  BUILD_LIBTEST_LIBRARIES_EXCLUDE += libFileUtils.c
    +endif
    +
     # This evaluation is expensive and should only be done if this target was
     # explicitly called.
     ifneq ($(filter build-test-lib-native, $(MAKECMDGOALS)), )
    diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk
    index d8bf596d38a..0a7b4cdd73c 100644
    --- a/make/test/JtregNativeHotspot.gmk
    +++ b/make/test/JtregNativeHotspot.gmk
    @@ -1,5 +1,5 @@
     #
    -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
    +# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
     # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     #
     # This code is free software; you can redistribute it and/or modify it
    @@ -858,6 +858,11 @@ else
           exeinvoke.c exestack-gap.c exestack-tls.c libAsyncGetCallTraceTest.cpp
     endif
     
    +ifeq ($(call And, $(call isTargetOs, linux) $(call isTargetCpu, aarch64)), false)
    +  BUILD_HOTSPOT_JTREG_EXCLUDE += libTestSVEWithJNI.c
    +endif
    +
    +
     BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exesigtest := -ljvm
     
     ifeq ($(call isTargetOs, windows), true)
    diff --git a/src/demo/share/jfc/J2Ddemo/java2d/Intro.java b/src/demo/share/jfc/J2Ddemo/java2d/Intro.java
    index 046768e3a6a..a4fd2e5b753 100644
    --- a/src/demo/share/jfc/J2Ddemo/java2d/Intro.java
    +++ b/src/demo/share/jfc/J2Ddemo/java2d/Intro.java
    @@ -1,6 +1,6 @@
     /*
      *
    - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are permitted provided that the following conditions
    @@ -1716,7 +1716,7 @@ public Contributors(int beg, int end, Surface surf) {
                     this.beginning = beg;
                     this.ending = end;
                     fm = surf.getMetrics(font);
    -                java.util.Arrays.sort(members);
    +                Arrays.sort(members);
                     cast.add("CONTRIBUTORS");
                     cast.add(" ");
                     cast.addAll(Arrays.asList(members));
    diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
    index ceb9cdf6f54..d89ef4c8124 100644
    --- a/src/hotspot/cpu/aarch64/aarch64.ad
    +++ b/src/hotspot/cpu/aarch64/aarch64.ad
    @@ -1,5 +1,5 @@
     //
    -// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
    +// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
     // Copyright (c) 2014, 2021, Red Hat, Inc. All rights reserved.
     // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     //
    @@ -8269,6 +8269,24 @@ instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{
       ins_pipe(pipe_class_default);
     %}
     
    +// ============================================================================
    +// VerifyVectorAlignment Instruction
    +
    +instruct verify_vector_alignment(iRegP addr, immL_positive_bitmaskI mask, rFlagsReg cr) %{
    +  match(Set addr (VerifyVectorAlignment addr mask));
    +  effect(KILL cr);
    +  format %{ "verify_vector_alignment $addr $mask \t! verify alignment" %}
    +  ins_encode %{
    +    Label Lskip;
    +    // check if masked bits of addr are zero
    +    __ tst($addr$$Register, $mask$$constant);
    +    __ br(Assembler::EQ, Lskip);
    +    __ stop("verify_vector_alignment found a misaligned vector memory access");
    +    __ bind(Lskip);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
     // ============================================================================
     // MemBar Instruction
     
    diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
    index 5a69934abd5..01ae45c3107 100644
    --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
    @@ -284,7 +284,8 @@ void LIR_Assembler::osr_entry() {
             __ bind(L);
           }
     #endif
    -      __ ldp(r19, r20, Address(OSR_buf, slot_offset));
    +      __ ldr(r19, Address(OSR_buf, slot_offset));
    +      __ ldr(r20, Address(OSR_buf, slot_offset + BytesPerWord));
           __ str(r19, frame_map()->address_for_monitor_lock(i));
           __ str(r20, frame_map()->address_for_monitor_object(i));
         }
    diff --git a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp
    index d1001687bd5..c58ff8828bc 100644
    --- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp
    @@ -28,6 +28,7 @@
     #include "code/compiledIC.hpp"
     #include "code/icBuffer.hpp"
     #include "code/nmethod.hpp"
    +#include "logging/log.hpp"
     #include "memory/resourceArea.hpp"
     #include "runtime/mutexLocker.hpp"
     #include "runtime/safepoint.hpp"
    @@ -90,9 +91,9 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
       address stub = find_stub();
       guarantee(stub != nullptr, "stub not found");
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
    +    log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                       p2i(instruction_address()),
                       callee->name_and_sig_as_C_string());
       }
    diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp
    index e0f04e3cf7b..8a08c2ebf14 100644
    --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp
    +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp
    @@ -159,8 +159,6 @@
       static void verify_deopt_original_pc(   CompiledMethod* nm, intptr_t* unextended_sp);
     #endif
     
    -  const ImmutableOopMap* get_oop_map() const;
    -
      public:
       // Constructors
     
    diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
    index 70d67b4aae2..7c5bc8b1f71 100644
    --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
    +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2014, Red Hat Inc. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
    @@ -198,7 +198,7 @@ inline bool frame::equal(frame other) const {
                   && unextended_sp() == other.unextended_sp()
                   && fp() == other.fp()
                   && pc() == other.pc();
    -  assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
    +  assert(!ret || (cb() == other.cb() && _deopt_state == other._deopt_state), "inconsistent construction");
       return ret;
     }
     
    @@ -362,20 +362,6 @@ inline int frame::sender_sp_ret_address_offset() {
       return frame::sender_sp_offset - frame::return_addr_offset;
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  if (_cb == nullptr) return nullptr;
    -  if (_cb->oop_maps() != nullptr) {
    -    NativePostCallNop* nop = nativePostCallNop_at(_pc);
    -    if (nop != nullptr && nop->displacement() != 0) {
    -      int slot = ((nop->displacement() >> 24) & 0xff);
    -      return _cb->oop_map_for_slot(slot, _pc);
    -    }
    -    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    -    return oop_map;
    -  }
    -  return nullptr;
    -}
    -
     //------------------------------------------------------------------------------
     // frame::sender
     inline frame frame::sender(RegisterMap* map) const {
    diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp
    index 2293d70c8da..63f6c9491c8 100644
    --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp
    +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp
    @@ -42,8 +42,12 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
     // and Operational Models for ARMv8"
     #define CPU_MULTI_COPY_ATOMIC
     
    +// The expected size in bytes of a cache line.
     #define DEFAULT_CACHE_LINE_SIZE 64
     
    +// The default padding size for data structures to avoid false sharing.
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
    +
     // According to the ARMv8 ARM, "Concurrent modification and execution
     // of instructions can lead to the resulting instruction performing
     // any behavior that can be achieved by executing any sequence of
    diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp
    index aa22459d217..08bff22d7d0 100644
    --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp
    +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp
    @@ -193,4 +193,9 @@
         }
       }
     
    +  // Is SIMD sort supported for this CPU?
    +  static bool supports_simd_sort(BasicType bt) {
    +    return false;
    +  }
    +
     #endif // CPU_AARCH64_MATCHER_AARCH64_HPP
    diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
    index 27bf35e12c8..a12caa3daee 100644
    --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
    @@ -560,18 +560,23 @@ static bool is_movk_to_zr(uint32_t insn) {
     }
     #endif
     
    -void NativePostCallNop::patch(jint diff) {
    +bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
    +  if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) {
    +    return false; // cannot encode
    +  }
    +  uint32_t data = ((uint32_t)oopmap_slot << 24) | cb_offset;
     #ifdef ASSERT
    -  assert(diff != 0, "must be");
    +  assert(data != 0, "must be");
       uint32_t insn1 = uint_at(4);
       uint32_t insn2 = uint_at(8);
       assert (is_movk_to_zr(insn1) && is_movk_to_zr(insn2), "must be");
     #endif
     
    -  uint32_t lo = diff & 0xffff;
    -  uint32_t hi = (uint32_t)diff >> 16;
    +  uint32_t lo = data & 0xffff;
    +  uint32_t hi = data >> 16;
       Instruction_aarch64::patch(addr_at(4), 20, 5, lo);
       Instruction_aarch64::patch(addr_at(8), 20, 5, hi);
    +  return true; // successfully encoded
     }
     
     void NativeDeoptInstruction::verify() {
    diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
    index 1740fde772f..c0be84d3f5c 100644
    --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
    +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
    @@ -691,16 +691,20 @@ class NativePostCallNop: public NativeInstruction {
         return (insns & 0xffe0001fffffffff) == 0xf280001fd503201f;
       }
     
    -  jint displacement() const {
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
         uint64_t movk_insns = *(uint64_t*)addr_at(4);
         uint32_t lo = (movk_insns >> 5) & 0xffff;
         uint32_t hi = (movk_insns >> (5 + 32)) & 0xffff;
    -    uint32_t result = (hi << 16) | lo;
    -
    -    return (jint)result;
    +    uint32_t data = (hi << 16) | lo;
    +    if (data == 0) {
    +      return false; // no information encoded
    +    }
    +    cb_offset = (data & 0xffffff);
    +    oopmap_slot = (data >> 24) & 0xff;
    +    return true; // decoding succeeded
       }
     
    -  void patch(jint diff);
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset);
       void make_deopt();
     };
     
    diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
    index 5ab36f92e19..4f7618adcf0 100644
    --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
    @@ -311,7 +311,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
     
       uint int_args = 0;
       uint fp_args = 0;
    -  uint stk_args = 0; // inc by 2 each time
    +  uint stk_args = 0;
     
       for (int i = 0; i < total_args_passed; i++) {
         switch (sig_bt[i]) {
    @@ -323,8 +323,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (int_args < Argument::n_int_register_parameters_j) {
             regs[i].set1(INT_ArgReg[int_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set1(VMRegImpl::stack2reg(stk_args));
    -        stk_args += 2;
    +        stk_args += 1;
           }
           break;
         case T_VOID:
    @@ -341,6 +342,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (int_args < Argument::n_int_register_parameters_j) {
             regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set2(VMRegImpl::stack2reg(stk_args));
             stk_args += 2;
           }
    @@ -349,8 +351,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (fp_args < Argument::n_float_register_parameters_j) {
             regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set1(VMRegImpl::stack2reg(stk_args));
    -        stk_args += 2;
    +        stk_args += 1;
           }
           break;
         case T_DOUBLE:
    @@ -358,6 +361,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (fp_args < Argument::n_float_register_parameters_j) {
             regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set2(VMRegImpl::stack2reg(stk_args));
             stk_args += 2;
           }
    @@ -368,7 +372,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
         }
       }
     
    -  return align_up(stk_args, 2);
    +  return stk_args;
     }
     
     
    diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
    index 68c66a32794..5c37401e867 100644
    --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
    @@ -3890,11 +3890,9 @@ void TemplateTable::_new() {
       // get InstanceKlass
       __ load_resolved_klass_at_offset(r4, r3, r4, rscratch1);
     
    -  // make sure klass is initialized & doesn't have finalizer
    -  // make sure klass is fully initialized
    -  __ ldrb(rscratch1, Address(r4, InstanceKlass::init_state_offset()));
    -  __ cmp(rscratch1, (u1)InstanceKlass::fully_initialized);
    -  __ br(Assembler::NE, slow_case);
    +  // make sure klass is initialized
    +  assert(VM_Version::supports_fast_class_init_checks(), "Optimization requires support for fast class initialization checks");
    +  __ clinit_barrier(r4, rscratch1, nullptr /*L_fast_path*/, &slow_case);
     
       __ allocate_instance(r4, r0, r3, r1, true, slow_case);
       __ b(done);
    diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
    index 8b67a207cf9..4b2e5cc5a4d 100644
    --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
    +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
    @@ -165,6 +165,7 @@ enum Ampere_CPU_Model {
       static int dcache_line_size() { return _dcache_line_size; }
       static int get_initial_sve_vector_length()  { return _initial_sve_vector_length; };
     
    +  // Aarch64 supports fast class initialization checks
       static bool supports_fast_class_init_checks() { return true; }
       constexpr static bool supports_stack_watermark_barrier() { return true; }
     
    diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad
    index c4197235987..e31ad91613a 100644
    --- a/src/hotspot/cpu/arm/arm.ad
    +++ b/src/hotspot/cpu/arm/arm.ad
    @@ -1,5 +1,5 @@
     //
    -// Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
    +// Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
     // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     //
     // This code is free software; you can redistribute it and/or modify it
    @@ -9193,7 +9193,7 @@ instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dum
       ins_encode %{
         __ mov($zero$$Register, 0);
         __ mov($temp$$Register, $cnt$$Register);
    -    Label(loop);
    +    Label loop;
         __ bind(loop);
         __ subs($temp$$Register, $temp$$Register, 4);
         __ str($zero$$Register, Address($base$$Register, $temp$$Register), ge);
    diff --git a/src/hotspot/cpu/arm/assembler_arm.hpp b/src/hotspot/cpu/arm/assembler_arm.hpp
    index b1b4199e88d..6a3092f7b3b 100644
    --- a/src/hotspot/cpu/arm/assembler_arm.hpp
    +++ b/src/hotspot/cpu/arm/assembler_arm.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -175,7 +175,7 @@ class Address {
         if (_index == noreg) {
           assert(-256 < _disp && _disp < 256, "encoding constraint");
           return _mode | up(_disp) << 23 | 1 << 22 | _base->encoding() << 16 |
    -             (abs(_disp) & 0xf0) << 4 | abs(_disp) & 0x0f;
    +             (abs(_disp) & 0xf0) << 4 | (abs(_disp) & 0x0f);
         } else {
           assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
           assert(_disp == 0 && _shift == lsl && _shift_imm == 0, "encoding constraint");
    diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    index 72f58275990..f2f11c52772 100644
    --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -2644,8 +2644,8 @@ 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) {
    -  assert(src->is_double_cpu() && dest->is_address() ||
    -         src->is_address() && dest->is_double_cpu(),
    +  assert((src->is_double_cpu() && dest->is_address()) ||
    +         (src->is_address() && dest->is_double_cpu()),
              "Simple move_op is called for all other cases");
     
       int null_check_offset;
    diff --git a/src/hotspot/cpu/arm/compiledIC_arm.cpp b/src/hotspot/cpu/arm/compiledIC_arm.cpp
    index 89eda97d7e2..2d4187b7d6c 100644
    --- a/src/hotspot/cpu/arm/compiledIC_arm.cpp
    +++ b/src/hotspot/cpu/arm/compiledIC_arm.cpp
    @@ -28,6 +28,7 @@
     #include "code/icBuffer.hpp"
     #include "code/nativeInst.hpp"
     #include "code/nmethod.hpp"
    +#include "logging/log.hpp"
     #include "memory/resourceArea.hpp"
     #include "runtime/mutexLocker.hpp"
     #include "runtime/safepoint.hpp"
    @@ -105,9 +106,9 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
       address stub = find_stub();
       guarantee(stub != nullptr, "stub not found");
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
    +    log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                       p2i(instruction_address()),
                       callee->name_and_sig_as_C_string());
       }
    diff --git a/src/hotspot/cpu/arm/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp
    index 7ef941ad0ff..56f8fc9932e 100644
    --- a/src/hotspot/cpu/arm/frame_arm.hpp
    +++ b/src/hotspot/cpu/arm/frame_arm.hpp
    @@ -99,8 +99,6 @@
       }
     #endif
     
    -  const ImmutableOopMap* get_oop_map() const;
    -
      public:
       // Constructors
     
    diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp
    index 9191d03baf0..8a08c0d0e9c 100644
    --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp
    +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -93,7 +93,7 @@ inline bool frame::equal(frame other) const {
                   && unextended_sp() == other.unextended_sp()
                   && fp() == other.fp()
                   && pc() == other.pc();
    -  assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
    +  assert(!ret || (cb() == other.cb() && _deopt_state == other._deopt_state), "inconsistent construction");
       return ret;
     }
     
    @@ -218,20 +218,6 @@ inline int frame::frame_size() const {
       return sender_sp() - sp();
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  if (_cb == nullptr) return nullptr;
    -  if (_cb->oop_maps() != nullptr) {
    -    NativePostCallNop* nop = nativePostCallNop_at(_pc);
    -    if (nop != nullptr && nop->displacement() != 0) {
    -      int slot = ((nop->displacement() >> 24) & 0xff);
    -      return _cb->oop_map_for_slot(slot, _pc);
    -    }
    -    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    -    return oop_map;
    -  }
    -  return nullptr;
    -}
    -
     inline int frame::compiled_frame_stack_argsize() const {
       Unimplemented();
       return 0;
    diff --git a/src/hotspot/cpu/arm/globalDefinitions_arm.hpp b/src/hotspot/cpu/arm/globalDefinitions_arm.hpp
    index 2041cf9e17e..5b68dbc9dbd 100644
    --- a/src/hotspot/cpu/arm/globalDefinitions_arm.hpp
    +++ b/src/hotspot/cpu/arm/globalDefinitions_arm.hpp
    @@ -49,8 +49,12 @@ const bool HaveVFP = true;
     // arm32 is not specified as multi-copy-atomic
     // So we must not #define CPU_MULTI_COPY_ATOMIC
     
    +// The expected size in bytes of a cache line.
     #define DEFAULT_CACHE_LINE_SIZE 64
     
    +// The default padding size for data structures to avoid false sharing.
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
    +
     #define STUBROUTINES_MD_HPP    "stubRoutines_arm.hpp"
     #define INTERP_MASM_MD_HPP     "interp_masm_arm.hpp"
     #define TEMPLATETABLE_MD_HPP   "templateTable_arm.hpp"
    diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp
    index 481c3d09e58..635acd781f9 100644
    --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp
    +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp
    @@ -303,15 +303,19 @@ void InterpreterMacroAssembler::load_field_entry(Register cache, Register index,
     }
     
     void InterpreterMacroAssembler::load_method_entry(Register cache, Register index, int bcp_offset) {
    +  assert_different_registers(cache, index);
    +
       // Get index out of bytecode pointer
       get_index_at_bcp(index, bcp_offset, cache /* as tmp */, sizeof(u2));
    +
    +  // sizeof(ResolvedMethodEntry) is not a power of 2 on Arm, so can't use shift
       mov(cache, sizeof(ResolvedMethodEntry));
       mul(index, index, cache); // Scale the index to be the entry index * sizeof(ResolvedMethodEntry)
     
       // load constant pool cache pointer
       ldr(cache, Address(FP, frame::interpreter_frame_cache_offset * wordSize));
       // Get address of method entries array
    -  ldr(cache, Address(cache, ConstantPoolCache::method_entries_offset()));
    +  ldr(cache, Address(cache, in_bytes(ConstantPoolCache::method_entries_offset())));
       add(cache, cache, Array::base_offset_in_bytes());
       add(cache, cache, index);
     }
    diff --git a/src/hotspot/cpu/arm/matcher_arm.hpp b/src/hotspot/cpu/arm/matcher_arm.hpp
    index 1e8f7683e76..eb26cbcbd7a 100644
    --- a/src/hotspot/cpu/arm/matcher_arm.hpp
    +++ b/src/hotspot/cpu/arm/matcher_arm.hpp
    @@ -186,4 +186,9 @@
         }
       }
     
    +  // Is SIMD sort supported for this CPU?
    +  static bool supports_simd_sort(BasicType bt) {
    +    return false;
    +  }
    +
     #endif // CPU_ARM_MATCHER_ARM_HPP
    diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp
    index e5e5e89c200..23ee01d3352 100644
    --- a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp
    +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -162,7 +162,7 @@ void NativeMovConstReg::set_data(intptr_t x, address pc) {
         unsigned int hi = (unsigned int)(x >> 16);
         this->set_encoding((this->encoding() & 0xfff0f000) | (lo & 0xf000) << 4 | (lo & 0xfff));
         next->set_encoding((next->encoding() & 0xfff0f000) | (hi & 0xf000) << 4 | (hi & 0xfff));
    -  } else if (oop_addr == nullptr & metadata_addr == nullptr) {
    +  } else if (oop_addr == nullptr && metadata_addr == nullptr) {
         // A static ldr_literal (without oop or metadata relocation)
         assert(is_ldr_literal(), "must be");
         int offset = ldr_offset();
    @@ -341,10 +341,6 @@ void NativePostCallNop::make_deopt() {
       NativeDeoptInstruction::insert(addr_at(0));
     }
     
    -void NativePostCallNop::patch(jint diff) {
    -  // unsupported for now
    -}
    -
     void NativeDeoptInstruction::verify() {
     }
     
    diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
    index 804292c24b0..7006d770981 100644
    --- a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
    +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -396,7 +396,7 @@ class NativeMovConstReg: public NativeInstruction {
     inline NativeMovConstReg* nativeMovConstReg_at(address address) {
       NativeInstruction* ni = nativeInstruction_at(address);
       assert(ni->is_ldr_literal() || ni->is_pc_rel() ||
    -         ni->is_movw() && VM_Version::supports_movw(), "must be");
    +         (ni->is_movw() && VM_Version::supports_movw()), "must be");
       return (NativeMovConstReg*)address;
     }
     
    @@ -438,8 +438,8 @@ inline NativeCall* nativeCall_before(address return_address) {
     class NativePostCallNop: public NativeInstruction {
     public:
       bool check() const { return is_nop(); }
    -  int displacement() const { return 0; }
    -  void patch(jint diff);
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const { return false; }
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset) { return false; }
       void make_deopt();
     };
     
    diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    index 9a65f9f09fe..716c7b7575e 100644
    --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    @@ -441,7 +441,6 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
         }
       }
     
    -  if (slot & 1) slot++;
       return slot;
     }
     
    diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp
    index ba9a3fd7a9b..efaf78ee568 100644
    --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp
    +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp
    @@ -370,17 +370,16 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
       if (index_size == sizeof(u4)) {
         __ load_resolved_indy_entry(Rcache, Rindex);
         __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset())));
    -    __ check_stack_top();
    -    __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize));
       } else {
         // Pop N words from the stack
         assert(index_size == sizeof(u2), "Can only be u2");
         __ load_method_entry(Rcache, Rindex);
    -    __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset())));
    -    __ check_stack_top();
    -    __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize));
    +    __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedMethodEntry::num_parameters_offset())));
       }
     
    +  __ check_stack_top();
    +  __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize));
    +
       __ convert_retval_to_tos(state);
     
       __ check_and_handle_popframe();
    diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp
    index e478f08c977..55a0120e7c7 100644
    --- a/src/hotspot/cpu/arm/templateTable_arm.cpp
    +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp
    @@ -3666,15 +3666,15 @@ void TemplateTable::prepare_invoke(Register Rcache, Register recv) {
       // load receiver if needed (after extra argument is pushed so parameter size is correct)
       if (load_receiver) {
         __ ldrh(recv, Address(Rcache, in_bytes(ResolvedMethodEntry::num_parameters_offset())));
    -    Address recv_addr = __ receiver_argument_address(Rstack_top, Rtemp, recv);
    -    __ ldr(recv, recv_addr);
    +    __ add(recv, Rstack_top, AsmOperand(recv, lsl, Interpreter::logStackElementSize));
    +    __ ldr(recv, Address(recv, -Interpreter::stackElementSize));
         __ verify_oop(recv);
       }
     
       // load return address
       { const address table = (address) Interpreter::invoke_return_entry_table_for(code);
    -    __ mov_slow(Rtemp, table);
    -    __ ldr(LR, Address::indexed_ptr(Rtemp, ret_type));
    +    __ mov_slow(LR, table);
    +    __ ldr(LR, Address::indexed_ptr(LR, ret_type));
       }
     }
     
    @@ -3744,10 +3744,13 @@ void TemplateTable::invokevirtual(int byte_no) {
     void TemplateTable::invokespecial(int byte_no) {
       transition(vtos, vtos);
       assert(byte_no == f1_byte, "use this argument");
    +
       const Register Rrecv  = R2_tmp;
    -  load_resolved_method_entry_special_or_static(R2_tmp,  // ResolvedMethodEntry*
    +  const Register Rflags = R3_tmp;
    +
    +  load_resolved_method_entry_special_or_static(Rrecv,  // ResolvedMethodEntry*
                                                    Rmethod, // Method*
    -                                               R3_tmp); // Flags
    +                                               Rflags); // Flags
       prepare_invoke(Rrecv, Rrecv);
       __ verify_oop(Rrecv);
       __ null_check(Rrecv, Rtemp);
    @@ -3760,12 +3763,16 @@ void TemplateTable::invokespecial(int byte_no) {
     void TemplateTable::invokestatic(int byte_no) {
       transition(vtos, vtos);
       assert(byte_no == f1_byte, "use this argument");
    -  load_resolved_method_entry_special_or_static(R2_tmp,  // ResolvedMethodEntry*
    +
    +  const Register Rrecv  = R2_tmp;
    +  const Register Rflags = R3_tmp;
    +
    +  load_resolved_method_entry_special_or_static(Rrecv,  // ResolvedMethodEntry*
                                                    Rmethod, // Method*
    -                                               R3_tmp); // Flags
    -  prepare_invoke(R2_tmp, R2_tmp);
    +                                               Rflags); // Flags
    +  prepare_invoke(Rrecv, Rrecv);
       // do the call
    -  __ profile_call(R2_tmp);
    +  __ profile_call(Rrecv);
       __ jump_from_interpreted(Rmethod);
     }
     
    @@ -3788,10 +3795,10 @@ void TemplateTable::invokeinterface(int byte_no) {
       const Register Rflags  = R3_tmp;
       const Register Rklass  = R2_tmp; // Note! Same register with Rrecv
     
    -  load_resolved_method_entry_interface(R2_tmp,  // ResolvedMethodEntry*
    -                                       R1_tmp,  // Klass*
    +  load_resolved_method_entry_interface(Rrecv,   // ResolvedMethodEntry*
    +                                       Rinterf, // Klass*
                                            Rmethod, // Method* or itable/vtable index
    -                                       R3_tmp); // Flags
    +                                       Rflags); // Flags
       prepare_invoke(Rrecv, Rrecv);
     
       // First check for Object case, then private interface method,
    diff --git a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp
    index 2e5548afcb1..54f9cfa9367 100644
    --- a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp
    +++ b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp
    @@ -167,9 +167,9 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
       address stub = find_stub();
       guarantee(stub != nullptr, "stub not found");
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
    +    log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                       p2i(instruction_address()),
                       callee->name_and_sig_as_C_string());
       }
    diff --git a/src/hotspot/cpu/ppc/frame_ppc.hpp b/src/hotspot/cpu/ppc/frame_ppc.hpp
    index e2e2b9d015d..d2c9927f119 100644
    --- a/src/hotspot/cpu/ppc/frame_ppc.hpp
    +++ b/src/hotspot/cpu/ppc/frame_ppc.hpp
    @@ -400,8 +400,6 @@
     
      public:
     
    -  const ImmutableOopMap* get_oop_map() const;
    -
       // Constructors
       inline frame(intptr_t* sp, intptr_t* fp, address pc);
       inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp = nullptr, intptr_t* fp = nullptr, CodeBlob* cb = nullptr);
    diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp
    index e7dca45b3c3..220b9c3241e 100644
    --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp
    +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp
    @@ -78,8 +78,8 @@ inline void frame::setup() {
       // Continuation frames on the java heap are not aligned.
       // When thawing interpreted frames the sp can be unaligned (see new_stack_frame()).
       assert(_on_heap ||
    -         (is_aligned(_sp, alignment_in_bytes) || is_interpreted_frame()) &&
    -         (is_aligned(_fp, alignment_in_bytes) || !is_fully_initialized()),
    +         ((is_aligned(_sp, alignment_in_bytes) || is_interpreted_frame()) &&
    +          (is_aligned(_fp, alignment_in_bytes) || !is_fully_initialized())),
              "invalid alignment sp:" PTR_FORMAT " unextended_sp:" PTR_FORMAT " fp:" PTR_FORMAT, p2i(_sp), p2i(_unextended_sp), p2i(_fp));
     }
     
    @@ -361,20 +361,6 @@ inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
       *result_adr = obj;
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  if (_cb == nullptr) return nullptr;
    -  if (_cb->oop_maps() != nullptr) {
    -    NativePostCallNop* nop = nativePostCallNop_at(_pc);
    -    if (nop != nullptr && nop->displacement() != 0) {
    -      int slot = ((nop->displacement() >> 24) & 0xff);
    -      return _cb->oop_map_for_slot(slot, _pc);
    -    }
    -    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    -    return oop_map;
    -  }
    -  return nullptr;
    -}
    -
     inline int frame::compiled_frame_stack_argsize() const {
       assert(cb()->is_compiled(), "");
       return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
    diff --git a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp
    index bced453d784..30670d053fa 100644
    --- a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp
    +++ b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp
    @@ -48,9 +48,12 @@ const bool CCallingConventionRequiresIntsAsLongs = true;
     // PPC64 is not specified as multi-copy-atomic
     // So we must not #define CPU_MULTI_COPY_ATOMIC
     
    -// The expected size in bytes of a cache line, used to pad data structures.
    +// The expected size in bytes of a cache line.
     #define DEFAULT_CACHE_LINE_SIZE 128
     
    +// The default padding size for data structures to avoid false sharing.
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
    +
     #define SUPPORT_RESERVED_STACK_AREA
     
     // If UseSIGTRAP is active, we only use the poll bit and no polling page.
    diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp
    index 44d1a3cd305..b195ba4eeb2 100644
    --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp
    +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp
    @@ -195,4 +195,9 @@
         }
       }
     
    +  // Is SIMD sort supported for this CPU?
    +  static bool supports_simd_sort(BasicType bt) {
    +    return false;
    +  }
    +
     #endif // CPU_PPC_MATCHER_PPC_HPP
    diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
    index f60f3f147ae..06754ccfdd7 100644
    --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
    +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
    @@ -429,10 +429,6 @@ void NativePostCallNop::make_deopt() {
       NativeDeoptInstruction::insert(addr_at(0));
     }
     
    -void NativePostCallNop::patch(jint diff) {
    -  // unsupported for now
    -}
    -
     void NativeDeoptInstruction::verify() {
     }
     
    diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
    index 378f4ea928a..ec6f5a90a72 100644
    --- a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
    +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
    @@ -508,8 +508,8 @@ class NativeMovRegMem: public NativeInstruction {
     class NativePostCallNop: public NativeInstruction {
     public:
       bool check() const { return is_nop(); }
    -  int displacement() const { return 0; }
    -  void patch(jint diff);
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const { return false; }
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset) { return false; }
       void make_deopt();
     };
     
    diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
    index 824996168a9..3382df355da 100644
    --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
    +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
    @@ -734,7 +734,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           ShouldNotReachHere();
         }
       }
    -  return align_up(stk, 2);
    +  return stk;
     }
     
     #if defined(COMPILER1) || defined(COMPILER2)
    diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ppc.hpp
    index b1168ded456..a5831ef1590 100644
    --- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp
    +++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp
    @@ -91,7 +91,7 @@ class VM_Version: public Abstract_VM_Version {
       // Override Abstract_VM_Version implementation
       static void print_platform_virtualization_info(outputStream*);
     
    -  // PPC64 supports fast class initialization checks for static methods.
    +  // PPC64 supports fast class initialization checks
       static bool supports_fast_class_init_checks() { return true; }
       constexpr static bool supports_stack_watermark_barrier() { return true; }
     
    diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp
    index 922e412356d..f44840d9f8c 100644
    --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
      * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    @@ -506,7 +506,7 @@ class Assembler : public AbstractAssembler {
       INSN(sllw,  0b0111011, 0b001, 0b0000000);
       INSN(sraw,  0b0111011, 0b101, 0b0100000);
       INSN(srlw,  0b0111011, 0b101, 0b0000000);
    -  INSN(mul,   0b0110011, 0b000, 0b0000001);
    +  INSN(_mul,  0b0110011, 0b000, 0b0000001);
       INSN(mulh,  0b0110011, 0b001, 0b0000001);
       INSN(mulhsu,0b0110011, 0b010, 0b0000001);
       INSN(mulhu, 0b0110011, 0b011, 0b0000001);
    @@ -537,9 +537,9 @@ class Assembler : public AbstractAssembler {
       }
     
       INSN(lb,  0b0000011, 0b000);
    -  INSN(lbu, 0b0000011, 0b100);
    -  INSN(lh,  0b0000011, 0b001);
    -  INSN(lhu, 0b0000011, 0b101);
    +  INSN(_lbu, 0b0000011, 0b100);
    +  INSN(_lh,  0b0000011, 0b001);
    +  INSN(_lhu, 0b0000011, 0b101);
       INSN(_lw, 0b0000011, 0b010);
       INSN(lwu, 0b0000011, 0b110);
       INSN(_ld, 0b0000011, 0b011);
    @@ -609,8 +609,8 @@ class Assembler : public AbstractAssembler {
         emit(insn);                                                                                             \
       }                                                                                                         \
     
    -  INSN(sb,   Register,      0b0100011, 0b000);
    -  INSN(sh,   Register,      0b0100011, 0b001);
    +  INSN(_sb,   Register,      0b0100011, 0b000);
    +  INSN(_sh,   Register,      0b0100011, 0b001);
       INSN(_sw,  Register,      0b0100011, 0b010);
       INSN(_sd,  Register,      0b0100011, 0b011);
       INSN(fsw,  FloatRegister, 0b0100111, 0b010);
    @@ -758,6 +758,8 @@ enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11};
       INSN(amomax_d , 0b0101111, 0b011, 0b10100);
       INSN(amominu_d, 0b0101111, 0b011, 0b11000);
       INSN(amomaxu_d, 0b0101111, 0b011, 0b11100);
    +  INSN(amocas_w,  0b0101111, 0b010, 0b00101);
    +  INSN(amocas_d,  0b0101111, 0b011, 0b00101);
     #undef INSN
     
     enum operand_size { int8, int16, int32, uint32, int64 };
    @@ -1154,10 +1156,8 @@ static Assembler::SEW elemtype_to_sew(BasicType etype) {
     }
     
     #define patch_vtype(hsb, lsb, vlmul, vsew, vta, vma, vill)   \
    -    if (vill == 1) {                                         \
    -      guarantee((vlmul | vsew | vta | vma == 0),             \
    -                "the other bits in vtype shall be zero");    \
    -    }                                                        \
    +    /* If vill then other bits of vtype must be zero. */     \
    +    guarantee(!vill, "vill not supported");                  \
         patch((address)&insn, lsb + 2, lsb, vlmul);              \
         patch((address)&insn, lsb + 5, lsb + 3, vsew);           \
         patch((address)&insn, lsb + 6, vta);                     \
    @@ -1332,6 +1332,7 @@ enum VectorMask {
       INSN(vsll_vi,    0b1010111, 0b011, 0b100101);
     
       // Vector Slide Instructions
    +  INSN(vslideup_vi,   0b1010111, 0b011, 0b001110);
       INSN(vslidedown_vi, 0b1010111, 0b011, 0b001111);
     
     #undef INSN
    @@ -1687,7 +1688,6 @@ enum VectorMask {
       INSN(vmv_v_x, 0b1010111, 0b100, v0, 0b1, 0b010111);
     
     #undef INSN
    -#undef patch_VArith
     
     #define INSN(NAME, op, funct13, funct6)                    \
       void NAME(VectorRegister Vd, VectorMask vm = unmasked) { \
    @@ -1729,14 +1729,29 @@ enum Nf {
         patch_reg((address)&insn, 15, Rs1);                                  \
         emit(insn)
     
    -#define INSN(NAME, op, lumop, vm, mop, nf)                                           \
    -  void NAME(VectorRegister Vd, Register Rs1, uint32_t width = 0, bool mew = false) { \
    +#define INSN(NAME, op, width, lumop, vm, mop, mew, nf)                               \
    +  void NAME(VectorRegister Vd, Register Rs1) {                                       \
         guarantee(is_uimm3(width), "width is invalid");                                  \
         patch_VLdSt(op, Vd, width, Rs1, lumop, vm, mop, mew, nf);                        \
       }
     
       // Vector Load/Store Instructions
    -  INSN(vl1re8_v, 0b0000111, 0b01000, 0b1, 0b00, g1);
    +  INSN(vl1re8_v,  0b0000111, 0b000, 0b01000, 0b1, 0b00, 0b0, g1);
    +  INSN(vl1re16_v, 0b0000111, 0b101, 0b01000, 0b1, 0b00, 0b0, g1);
    +  INSN(vl1re32_v, 0b0000111, 0b110, 0b01000, 0b1, 0b00, 0b0, g1);
    +  INSN(vl1re64_v, 0b0000111, 0b111, 0b01000, 0b1, 0b00, 0b0, g1);
    +  INSN(vl2re8_v,  0b0000111, 0b000, 0b01000, 0b1, 0b00, 0b0, g2);
    +  INSN(vl2re16_v, 0b0000111, 0b101, 0b01000, 0b1, 0b00, 0b0, g2);
    +  INSN(vl2re32_v, 0b0000111, 0b110, 0b01000, 0b1, 0b00, 0b0, g2);
    +  INSN(vl2re64_v, 0b0000111, 0b111, 0b01000, 0b1, 0b00, 0b0, g2);
    +  INSN(vl4re8_v,  0b0000111, 0b000, 0b01000, 0b1, 0b00, 0b0, g4);
    +  INSN(vl4re16_v, 0b0000111, 0b101, 0b01000, 0b1, 0b00, 0b0, g4);
    +  INSN(vl4re32_v, 0b0000111, 0b110, 0b01000, 0b1, 0b00, 0b0, g4);
    +  INSN(vl4re64_v, 0b0000111, 0b111, 0b01000, 0b1, 0b00, 0b0, g4);
    +  INSN(vl8re8_v,  0b0000111, 0b000, 0b01000, 0b1, 0b00, 0b0, g8);
    +  INSN(vl8re16_v, 0b0000111, 0b101, 0b01000, 0b1, 0b00, 0b0, g8);
    +  INSN(vl8re32_v, 0b0000111, 0b110, 0b01000, 0b1, 0b00, 0b0, g8);
    +  INSN(vl8re64_v, 0b0000111, 0b111, 0b01000, 0b1, 0b00, 0b0, g8);
     
     #undef INSN
     
    @@ -1747,6 +1762,9 @@ enum Nf {
     
       // Vector Load/Store Instructions
       INSN(vs1r_v, 0b0100111, 0b000, 0b01000, 0b1, 0b00, 0b0, g1);
    +  INSN(vs2r_v, 0b0100111, 0b000, 0b01000, 0b1, 0b00, 0b0, g2);
    +  INSN(vs4r_v, 0b0100111, 0b000, 0b01000, 0b1, 0b00, 0b0, g4);
    +  INSN(vs8r_v, 0b0100111, 0b000, 0b01000, 0b1, 0b00, 0b0, g8);
     
     #undef INSN
     
    @@ -1792,9 +1810,11 @@ enum Nf {
       }
     
       // Vector unordered indexed load instructions
    +  INSN( vluxei8_v, 0b0000111, 0b000, 0b01, 0b0);
       INSN(vluxei32_v, 0b0000111, 0b110, 0b01, 0b0);
     
       // Vector unordered indexed store instructions
    +  INSN( vsuxei8_v, 0b0100111, 0b000, 0b01, 0b0);
       INSN(vsuxei32_v, 0b0100111, 0b110, 0b01, 0b0);
     
     #undef INSN
    @@ -1818,6 +1838,55 @@ enum Nf {
     #undef INSN
     #undef patch_VLdSt
     
    +// ====================================
    +// RISC-V Vector Crypto Extension
    +// ====================================
    +
    +#define INSN(NAME, op, funct3, funct6)                                                             \
    +  void NAME(VectorRegister Vd, VectorRegister Vs2, VectorRegister Vs1, VectorMask vm = unmasked) { \
    +    patch_VArith(op, Vd, funct3, Vs1->raw_encoding(), Vs2, vm, funct6);                            \
    +  }
    +
    +  // Vector Bit-manipulation used in Cryptography (Zvkb) Extension
    +  INSN(vandn_vv,   0b1010111, 0b000, 0b000001);
    +  INSN(vandn_vx,   0b1010111, 0b100, 0b000001);
    +  INSN(vandn_vi,   0b1010111, 0b011, 0b000001);
    +  INSN(vclmul_vv,  0b1010111, 0b010, 0b001100);
    +  INSN(vclmul_vx,  0b1010111, 0b110, 0b001100);
    +  INSN(vclmulh_vv, 0b1010111, 0b010, 0b001101);
    +  INSN(vclmulh_vx, 0b1010111, 0b110, 0b001101);
    +  INSN(vror_vv,    0b1010111, 0b000, 0b010100);
    +  INSN(vror_vx,    0b1010111, 0b100, 0b010100);
    +  INSN(vrol_vv,    0b1010111, 0b000, 0b010101);
    +  INSN(vrol_vx,    0b1010111, 0b100, 0b010101);
    +
    +#undef INSN
    +
    +#define INSN(NAME, op, funct3, Vs1, funct6)                                    \
    +  void NAME(VectorRegister Vd, VectorRegister Vs2, VectorMask vm = unmasked) { \
    +    patch_VArith(op, Vd, funct3, Vs1, Vs2, vm, funct6);                        \
    +  }
    +
    +  // Vector Bit-manipulation used in Cryptography (Zvkb) Extension
    +  INSN(vbrev8_v, 0b1010111, 0b010, 0b01000, 0b010010);
    +  INSN(vrev8_v,  0b1010111, 0b010, 0b01001, 0b010010);
    +
    +#undef INSN
    +
    +#define INSN(NAME, op, funct3, vm, funct6)                                   \
    +  void NAME(VectorRegister Vd, VectorRegister Vs2, VectorRegister Vs1) {     \
    +    patch_VArith(op, Vd, funct3, Vs1->raw_encoding(), Vs2, vm, funct6);      \
    +  }
    +
    +  // Vector SHA-2 Secure Hash (Zvknh[ab]) Extension
    +  INSN(vsha2ms_vv,  0b1110111, 0b010, 0b1, 0b101101);
    +  INSN(vsha2ch_vv,  0b1110111, 0b010, 0b1, 0b101110);
    +  INSN(vsha2cl_vv,  0b1110111, 0b010, 0b1, 0b101111);
    +
    +#undef INSN
    +
    +#undef patch_VArith
    +
     // ====================================
     // RISC-V Bit-Manipulation Extension
     // Currently only support Zba, Zbb and Zbs bitmanip extensions.
    @@ -1867,9 +1936,9 @@ enum Nf {
       }
     
       INSN(rev8,   0b0010011, 0b101, 0b011010111000);
    -  INSN(sext_b, 0b0010011, 0b001, 0b011000000100);
    -  INSN(sext_h, 0b0010011, 0b001, 0b011000000101);
    -  INSN(zext_h, 0b0111011, 0b100, 0b000010000000);
    +  INSN(_sext_b, 0b0010011, 0b001, 0b011000000100);
    +  INSN(_sext_h, 0b0010011, 0b001, 0b011000000101);
    +  INSN(_zext_h, 0b0111011, 0b100, 0b000010000000);
       INSN(clz,    0b0010011, 0b001, 0b011000000000);
       INSN(clzw,   0b0011011, 0b001, 0b011000000000);
       INSN(ctz,    0b0010011, 0b001, 0b011000000001);
    @@ -2581,6 +2650,15 @@ enum Nf {
         return UseRVC && in_compressible_region();
       }
     
    +  bool do_compress_zcb(Register reg1 = noreg, Register reg2 = noreg) const {
    +    return do_compress() && VM_Version::ext_Zcb.enabled() &&
    +           (reg1 == noreg || reg1->is_compressed_valid()) && (reg2 == noreg || reg2->is_compressed_valid());
    +  }
    +
    +  bool do_compress_zcb_zbb(Register reg1 = noreg, Register reg2 = noreg) const {
    +    return do_compress_zcb(reg1, reg2) && UseZbb;
    +  }
    +
     // --------------------------
     // Load/store register
     // --------------------------
    @@ -2915,6 +2993,238 @@ enum Nf {
     
     #undef INSN
     
    +// --------------  ZCB Instruction Definitions  --------------
    +// Zcb additional C instructions
    + private:
    +  // Format CLH, c.lh/c.lhu
    +  template 
    +  void c_lh_if(Register Rd_Rs2, Register Rs1, uint32_t uimm) {
    +    assert_cond(uimm == 0 || uimm == 2);
    +    assert_cond(do_compress_zcb(Rd_Rs2, Rs1));
    +    uint16_t insn = 0;
    +    c_patch((address)&insn, 1, 0, 0b00);
    +    c_patch_compressed_reg((address)&insn, 2, Rd_Rs2);
    +    c_patch((address)&insn, 5, 5, (uimm & nth_bit(1)) >> 1);
    +    c_patch((address)&insn, 6, 6, Unsigned ? 0 : 1);
    +    c_patch_compressed_reg((address)&insn, 7, Rs1);
    +    c_patch((address)&insn, 12, 10, 0b001);
    +    c_patch((address)&insn, 15, 13, 0b100);
    +    emit_int16(insn);
    +  }
    +
    +  template 
    +  void lh_c_mux(Register Rd_Rs2, Register Rs1, const int32_t uimm) {
    +    if (do_compress_zcb(Rd_Rs2, Rs1) &&
    +        (uimm == 0 || uimm == 2)) {
    +      c_lh_if(Rd_Rs2, Rs1, uimm);
    +    } else {
    +      if (Unsigned) {
    +        _lhu(Rd_Rs2, Rs1, uimm);
    +      } else {
    +        _lh(Rd_Rs2, Rs1, uimm);
    +      }
    +    }
    +  }
    +
    +  // Format CU, c.[sz]ext.*, c.not
    +  template 
    +  void c_u_if(Register Rs1) {
    +    assert_cond(do_compress_zcb(Rs1));
    +    uint16_t insn = 0;
    +    c_patch((address)&insn, 1, 0, 0b01);
    +    c_patch((address)&insn, 4, 2, InstructionType);
    +    c_patch((address)&insn, 6, 5, 0b11);
    +    c_patch_compressed_reg((address)&insn, 7, Rs1);
    +    c_patch((address)&insn, 12, 10, 0b111);
    +    c_patch((address)&insn, 15, 13, 0b100);
    +    emit_int16(insn);
    +  }
    +
    + public:
    +
    +  // Prerequisites: Zcb
    +  void c_lh(Register Rd_Rs2, Register Rs1, const int32_t uimm)  {  c_lh_if(Rd_Rs2, Rs1, uimm); }
    +  void lh(Register Rd_Rs2, Register Rs1, const int32_t uimm)    { lh_c_mux(Rd_Rs2, Rs1, uimm); }
    +
    +  // Prerequisites: Zcb
    +  void c_lhu(Register Rd_Rs2, Register Rs1, const int32_t uimm) {  c_lh_if(Rd_Rs2, Rs1, uimm); }
    +  void lhu(Register Rd_Rs2, Register Rs1, const int32_t uimm)   { lh_c_mux(Rd_Rs2, Rs1, uimm); }
    +
    +  // Prerequisites: Zcb
    +  // Format CLB, single instruction
    +  void c_lbu(Register Rd_Rs2, Register Rs1, uint32_t uimm) {
    +    assert_cond(uimm <= 3);
    +    assert_cond(do_compress_zcb(Rd_Rs2, Rs1));
    +    uint16_t insn = 0;
    +    c_patch((address)&insn, 1, 0, 0b00);
    +    c_patch_compressed_reg((address)&insn, 2, Rd_Rs2);
    +    c_patch((address)&insn, 5, 5, (uimm & nth_bit(1)) >> 1);
    +    c_patch((address)&insn, 6, 6, (uimm & nth_bit(0)) >> 0);
    +    c_patch_compressed_reg((address)&insn, 7, Rs1);
    +    c_patch((address)&insn, 12, 10, 0b000);
    +    c_patch((address)&insn, 15, 13, 0b100);
    +    emit_int16(insn);
    +  }
    +
    +  void lbu(Register Rd_Rs2, Register Rs1, const int32_t uimm) {
    +    if (do_compress_zcb(Rd_Rs2, Rs1) &&
    +        uimm >= 0 && uimm <= 3) {
    +      c_lbu(Rd_Rs2, Rs1, uimm);
    +    } else {
    +      _lbu(Rd_Rs2, Rs1, uimm);
    +    }
    +  }
    +
    +  // Prerequisites: Zcb
    +  // Format CSB, single instruction
    +  void c_sb(Register Rd_Rs2, Register Rs1, uint32_t uimm) {
    +    assert_cond(uimm <= 3);
    +    assert_cond(do_compress_zcb(Rd_Rs2, Rs1));
    +    uint16_t insn = 0;
    +    c_patch((address)&insn, 1, 0, 0b00);
    +    c_patch_compressed_reg((address)&insn, 2, Rd_Rs2);
    +    c_patch((address)&insn, 5, 5, (uimm & nth_bit(1)) >> 1);
    +    c_patch((address)&insn, 6, 6, (uimm & nth_bit(0)) >> 0);
    +    c_patch_compressed_reg((address)&insn, 7, Rs1);
    +    c_patch((address)&insn, 12, 10, 0b010);
    +    c_patch((address)&insn, 15, 13, 0b100);
    +    emit_int16(insn);
    +  }
    +
    +  void sb(Register Rd_Rs2, Register Rs1, const int32_t uimm) {
    +    if (do_compress_zcb(Rd_Rs2, Rs1) &&
    +        uimm >= 0 && uimm <= 3) {
    +      c_sb(Rd_Rs2, Rs1, uimm);
    +    } else {
    +      _sb(Rd_Rs2, Rs1, uimm);
    +    }
    +  }
    +
    +  // Prerequisites: Zcb
    +  // Format CSH, single instruction
    +  void c_sh(Register Rd_Rs2, Register Rs1, uint32_t uimm) {
    +    assert_cond(uimm == 0 || uimm == 2);
    +    assert_cond(do_compress_zcb(Rd_Rs2, Rs1));
    +    uint16_t insn = 0;
    +    c_patch((address)&insn, 1, 0, 0b00);
    +    c_patch_compressed_reg((address)&insn, 2, Rd_Rs2);
    +    c_patch((address)&insn, 5, 5, (uimm & nth_bit(1)) >> 1);
    +    c_patch((address)&insn, 6, 6, 0);
    +    c_patch_compressed_reg((address)&insn, 7, Rs1);
    +    c_patch((address)&insn, 12, 10, 0b011);
    +    c_patch((address)&insn, 15, 13, 0b100);
    +    emit_int16(insn);
    +  }
    +
    +  void sh(Register Rd_Rs2, Register Rs1, const int32_t uimm) {
    +    if (do_compress_zcb(Rd_Rs2, Rs1) &&
    +        (uimm == 0 || uimm == 2)) {
    +      c_sh(Rd_Rs2, Rs1, uimm);
    +    } else {
    +      _sh(Rd_Rs2, Rs1, uimm);
    +    }
    +  }
    +
    +  // Prerequisites: Zcb
    +  // Format CS
    +  void c_zext_b(Register Rs1) {
    +    assert_cond(do_compress_zcb(Rs1));
    +    c_u_if<0b000>(Rs1);
    +  }
    +
    +  // Prerequisites: Zbb
    +  void sext_b(Register Rd_Rs2, Register Rs1) {
    +    assert_cond(UseZbb);
    +    if (do_compress_zcb_zbb(Rd_Rs2, Rs1) && (Rd_Rs2 == Rs1)) {
    +      c_sext_b(Rd_Rs2);
    +    } else {
    +      _sext_b(Rd_Rs2, Rs1);
    +    }
    +  }
    +
    +  // Prerequisites: Zcb, Zbb
    +  // Format CS
    +  void c_sext_b(Register Rs1) {
    +    c_u_if<0b001>(Rs1);
    +  }
    +
    +  // Prerequisites: Zbb
    +  void zext_h(Register Rd_Rs2, Register Rs1) {
    +    assert_cond(UseZbb);
    +    if (do_compress_zcb_zbb(Rd_Rs2, Rs1) && (Rd_Rs2 == Rs1)) {
    +      c_zext_h(Rd_Rs2);
    +    } else {
    +      _zext_h(Rd_Rs2, Rs1);
    +    }
    +  }
    +
    +  // Prerequisites: Zcb, Zbb
    +  // Format CS
    +  void c_zext_h(Register Rs1) {
    +    c_u_if<0b010>(Rs1);
    +  }
    +
    +  // Prerequisites: Zbb
    +  void sext_h(Register Rd_Rs2, Register Rs1) {
    +    assert_cond(UseZbb);
    +    if (do_compress_zcb_zbb(Rd_Rs2, Rs1) && (Rd_Rs2 == Rs1)) {
    +      c_sext_h(Rd_Rs2);
    +    } else {
    +      _sext_h(Rd_Rs2, Rs1);
    +    }
    +  }
    +
    +  // Prerequisites: Zcb, Zbb
    +  // Format CS
    +  void c_sext_h(Register Rs1) {
    +    c_u_if<0b011>(Rs1);
    +  }
    +
    +  // Prerequisites: Zcb, Zba
    +  // Format CS
    +  void c_zext_w(Register Rs1) {
    +    c_u_if<0b100>(Rs1);
    +  }
    +
    +  // Prerequisites: Zcb
    +  // Format CS
    +  void c_not(Register Rs1) {
    +    c_u_if<0b101>(Rs1);
    +  }
    +
    +  // Prerequisites: Zcb (M or Zmmul)
    +  // Format CA, c.mul
    +  void c_mul(Register Rd_Rs1, Register Rs2) {
    +    uint16_t insn = 0;
    +    c_patch((address)&insn, 1, 0, 0b01);
    +    c_patch_compressed_reg((address)&insn, 2, Rs2);
    +    c_patch((address)&insn, 6, 5, 0b10);
    +    c_patch_compressed_reg((address)&insn, 7, Rd_Rs1);
    +    c_patch((address)&insn, 12, 10, 0b111);
    +    c_patch((address)&insn, 15, 13, 0b100);
    +    emit_int16(insn);
    +  }
    +
    +  void mul(Register Rd, Register Rs1, Register Rs2) {
    +    if (Rd != Rs1 && Rd != Rs2) {
    +      // Three registers needed without a mv, emit uncompressed
    +      _mul(Rd, Rs1, Rs2);
    +      return;
    +    }
    +
    +    // Rd is either Rs1 or Rs2
    +    if (!do_compress_zcb(Rs2, Rs1)) {
    +      _mul(Rd, Rs1, Rs2);
    +    } else {
    +      if (Rd == Rs2) {
    +        Rs2 = Rs1;
    +      } else {
    +        assert(Rd == Rs1, "must be");
    +      }
    +      c_mul(Rd, Rs2);
    +    }
    +  }
    +
       // Stack overflow checking
       virtual void bang_stack_with_offset(int offset) { Unimplemented(); }
     
    @@ -2940,6 +3250,17 @@ enum Nf {
         return uabs(target - branch) < branch_range;
       }
     
    +  // Decode the given instruction, checking if it's a 16-bit compressed
    +  // instruction and return the address of the next instruction.
    +  static address locate_next_instruction(address inst) {
    +    // Instruction wider than 16 bits has the two least-significant bits set.
    +    if ((0x3 & *inst) == 0x3) {
    +      return inst + instruction_size;
    +    } else {
    +      return inst + compressed_instruction_size;
    +    }
    +  }
    +
       Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(true) {}
     };
     
    diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
    index ab84ef7f8a1..711eb210091 100644
    --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
    @@ -1459,6 +1459,112 @@ void C2_MacroAssembler::string_equals(Register a1, Register a2,
       BLOCK_COMMENT("} string_equals");
     }
     
    +// jdk.internal.util.ArraysSupport.vectorizedHashCode
    +void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register result,
    +                                        Register tmp1, Register tmp2, Register tmp3,
    +                                        Register tmp4, Register tmp5, Register tmp6,
    +                                        BasicType eltype)
    +{
    +  assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, t0, t1);
    +
    +  const int elsize = arrays_hashcode_elsize(eltype);
    +  const int chunks_end_shift = exact_log2(elsize);
    +
    +  switch (eltype) {
    +  case T_BOOLEAN: BLOCK_COMMENT("arrays_hashcode(unsigned byte) {"); break;
    +  case T_CHAR:    BLOCK_COMMENT("arrays_hashcode(char) {");          break;
    +  case T_BYTE:    BLOCK_COMMENT("arrays_hashcode(byte) {");          break;
    +  case T_SHORT:   BLOCK_COMMENT("arrays_hashcode(short) {");         break;
    +  case T_INT:     BLOCK_COMMENT("arrays_hashcode(int) {");           break;
    +  default:
    +    ShouldNotReachHere();
    +  }
    +
    +  const int stride = 4;
    +  const Register pow31_4 = tmp1;
    +  const Register pow31_3 = tmp2;
    +  const Register pow31_2 = tmp3;
    +  const Register chunks  = tmp4;
    +  const Register chunks_end = chunks;
    +
    +  Label DONE, TAIL, TAIL_LOOP, WIDE_LOOP;
    +
    +  // result has a value initially
    +
    +  beqz(cnt, DONE);
    +
    +  andi(chunks, cnt, ~(stride-1));
    +  beqz(chunks, TAIL);
    +
    +  mv(pow31_4, 923521);           // [31^^4]
    +  mv(pow31_3,  29791);           // [31^^3]
    +  mv(pow31_2,    961);           // [31^^2]
    +
    +  slli(chunks_end, chunks, chunks_end_shift);
    +  add(chunks_end, ary, chunks_end);
    +  andi(cnt, cnt, stride-1);      // don't forget about tail!
    +
    +  bind(WIDE_LOOP);
    +  mulw(result, result, pow31_4); // 31^^4 * h
    +  arrays_hashcode_elload(t0,   Address(ary, 0 * elsize), eltype);
    +  arrays_hashcode_elload(t1,   Address(ary, 1 * elsize), eltype);
    +  arrays_hashcode_elload(tmp5, Address(ary, 2 * elsize), eltype);
    +  arrays_hashcode_elload(tmp6, Address(ary, 3 * elsize), eltype);
    +  mulw(t0, t0, pow31_3);         // 31^^3 * ary[i+0]
    +  addw(result, result, t0);
    +  mulw(t1, t1, pow31_2);         // 31^^2 * ary[i+1]
    +  addw(result, result, t1);
    +  slli(t0, tmp5, 5);             // optimize 31^^1 * ary[i+2]
    +  subw(tmp5, t0, tmp5);          // with ary[i+2]<<5 - ary[i+2]
    +  addw(result, result, tmp5);
    +  addw(result, result, tmp6);    // 31^^4 * h + 31^^3 * ary[i+0] + 31^^2 * ary[i+1]
    +                                 //           + 31^^1 * ary[i+2] + 31^^0 * ary[i+3]
    +  addi(ary, ary, elsize * stride);
    +  bne(ary, chunks_end, WIDE_LOOP);
    +  beqz(cnt, DONE);
    +
    +  bind(TAIL);
    +  slli(chunks_end, cnt, chunks_end_shift);
    +  add(chunks_end, ary, chunks_end);
    +
    +  bind(TAIL_LOOP);
    +  arrays_hashcode_elload(t0, Address(ary), eltype);
    +  slli(t1, result, 5);           // optimize 31 * result
    +  subw(result, t1, result);      // with result<<5 - result
    +  addw(result, result, t0);
    +  addi(ary, ary, elsize);
    +  bne(ary, chunks_end, TAIL_LOOP);
    +
    +  bind(DONE);
    +  BLOCK_COMMENT("} // arrays_hashcode");
    +}
    +
    +int C2_MacroAssembler::arrays_hashcode_elsize(BasicType eltype) {
    +  switch (eltype) {
    +  case T_BOOLEAN: return sizeof(jboolean);
    +  case T_BYTE:    return sizeof(jbyte);
    +  case T_SHORT:   return sizeof(jshort);
    +  case T_CHAR:    return sizeof(jchar);
    +  case T_INT:     return sizeof(jint);
    +  default:
    +    ShouldNotReachHere();
    +    return -1;
    +  }
    +}
    +
    +void C2_MacroAssembler::arrays_hashcode_elload(Register dst, Address src, BasicType eltype) {
    +  switch (eltype) {
    +  // T_BOOLEAN used as surrogate for unsigned byte
    +  case T_BOOLEAN: lbu(dst, src);   break;
    +  case T_BYTE:     lb(dst, src);   break;
    +  case T_SHORT:    lh(dst, src);   break;
    +  case T_CHAR:    lhu(dst, src);   break;
    +  case T_INT:      lw(dst, src);   break;
    +  default:
    +    ShouldNotReachHere();
    +  }
    +}
    +
     typedef void (Assembler::*conditional_branch_insn)(Register op1, Register op2, Label& label, bool is_far);
     typedef void (MacroAssembler::*float_conditional_branch_insn)(FloatRegister op1, FloatRegister op2, Label& label,
                                                                   bool is_far, bool is_unordered);
    diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
    index b9a7749631a..4940ce5fe9e 100644
    --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
    @@ -82,6 +82,15 @@
                          Register result, Register cnt1,
                          int elem_size);
     
    +  void arrays_hashcode(Register ary, Register cnt, Register result,
    +                       Register tmp1, Register tmp2,
    +                       Register tmp3, Register tmp4,
    +                       Register tmp5, Register tmp6,
    +                       BasicType eltype);
    +  // helper function for arrays_hashcode
    +  int arrays_hashcode_elsize(BasicType eltype);
    +  void arrays_hashcode_elload(Register dst, Address src, BasicType eltype);
    +
       void string_equals(Register r1, Register r2,
                          Register result, Register cnt1,
                          int elem_size);
    diff --git a/src/hotspot/cpu/riscv/compiledIC_riscv.cpp b/src/hotspot/cpu/riscv/compiledIC_riscv.cpp
    index 4239ca6e383..e29dee56de8 100644
    --- a/src/hotspot/cpu/riscv/compiledIC_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/compiledIC_riscv.cpp
    @@ -29,6 +29,7 @@
     #include "code/compiledIC.hpp"
     #include "code/icBuffer.hpp"
     #include "code/nmethod.hpp"
    +#include "logging/log.hpp"
     #include "memory/resourceArea.hpp"
     #include "runtime/mutexLocker.hpp"
     #include "runtime/safepoint.hpp"
    @@ -88,9 +89,9 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
       address stub = find_stub();
       guarantee(stub != nullptr, "stub not found");
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
    +    log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                       p2i(instruction_address()),
                       callee->name_and_sig_as_C_string());
       }
    diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp
    index ae6242a75bd..0c0659d1eee 100644
    --- a/src/hotspot/cpu/riscv/frame_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/frame_riscv.hpp
    @@ -189,8 +189,6 @@
       static void verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp);
     #endif
     
    -  const ImmutableOopMap* get_oop_map() const;
    -
      public:
       // Constructors
     
    diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp
    index dfec3880192..33727a8c6d0 100644
    --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp
    +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2014, Red Hat Inc. All rights reserved.
      * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    @@ -186,7 +186,7 @@ inline bool frame::equal(frame other) const {
                   unextended_sp() == other.unextended_sp() &&
                   fp() == other.fp() &&
                   pc() == other.pc();
    -  assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
    +  assert(!ret || (cb() == other.cb() && _deopt_state == other._deopt_state), "inconsistent construction");
       return ret;
     }
     
    @@ -345,20 +345,6 @@ inline int frame::sender_sp_ret_address_offset() {
       return frame::sender_sp_offset - frame::return_addr_offset;
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  if (_cb == nullptr) return nullptr;
    -  if (_cb->oop_maps() != nullptr) {
    -    NativePostCallNop* nop = nativePostCallNop_at(_pc);
    -    if (nop != nullptr && nop->displacement() != 0) {
    -      int slot = ((nop->displacement() >> 24) & 0xff);
    -      return _cb->oop_map_for_slot(slot, _pc);
    -    }
    -    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    -    return oop_map;
    -  }
    -  return nullptr;
    -}
    -
     //------------------------------------------------------------------------------
     // frame::sender
     frame frame::sender(RegisterMap* map) const {
    diff --git a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad
    index 73d337bc484..3d0273109ac 100644
    --- a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad
    +++ b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad
    @@ -52,11 +52,11 @@ static void x_load_barrier_slow_path(MacroAssembler& _masm, const MachNode* node
     %}
     
     // Load Pointer
    -instruct xLoadP(iRegPNoSp dst, memory mem)
    +instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp)
     %{
       match(Set dst (LoadP mem));
       predicate(UseZGC && !ZGenerational && (n->as_Load()->barrier_data() != 0));
    -  effect(TEMP dst);
    +  effect(TEMP dst, TEMP tmp);
     
       ins_cost(4 * DEFAULT_COST);
     
    @@ -65,17 +65,17 @@ instruct xLoadP(iRegPNoSp dst, memory mem)
       ins_encode %{
         const Address ref_addr (as_Register($mem$$base), $mem$$disp);
         __ ld($dst$$Register, ref_addr);
    -    x_load_barrier(_masm, this, ref_addr, $dst$$Register, t0 /* tmp */, barrier_data());
    +    x_load_barrier(_masm, this, ref_addr, $dst$$Register, $tmp$$Register /* tmp */, barrier_data());
       %}
     
       ins_pipe(iload_reg_mem);
     %}
     
    -instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
       match(Set res (CompareAndSwapP mem (Binary oldval newval)));
       match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
       predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong);
    -  effect(KILL cr, TEMP_DEF res);
    +  effect(TEMP_DEF res, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -86,17 +86,15 @@ instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva
         Label failed;
         guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
         __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
    -               Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register,
    -               true /* result_as_bool */);
    -    __ beqz($res$$Register, failed);
    -    __ mv(t0, $oldval$$Register);
    -    __ bind(failed);
    +               Assembler::relaxed /* acquire */, Assembler::rl /* release */, $tmp$$Register);
    +    __ sub(t0, $tmp$$Register, $oldval$$Register);
    +    __ seqz($res$$Register, t0);
         if (barrier_data() != XLoadBarrierElided) {
           Label good;
    -      __ ld(t1, Address(xthread, XThreadLocalData::address_bad_mask_offset()), t1 /* tmp */);
    -      __ andr(t1, t1, t0);
    -      __ beqz(t1, good);
    -      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), t0 /* ref */, t1 /* tmp */);
    +      __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset()));
    +      __ andr(t0, t0, $tmp$$Register);
    +      __ beqz(t0, good);
    +      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), $tmp$$Register /* ref */, $res$$Register /* tmp */);
           __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
                      Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register,
                      true /* result_as_bool */);
    @@ -107,11 +105,11 @@ instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva
       ins_pipe(pipe_slow);
     %}
     
    -instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
       match(Set res (CompareAndSwapP mem (Binary oldval newval)));
       match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
       predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == XLoadBarrierStrong));
    -  effect(KILL cr, TEMP_DEF res);
    +  effect(TEMP_DEF res, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -122,17 +120,15 @@ instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
         Label failed;
         guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
         __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
    -               Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register,
    -               true /* result_as_bool */);
    -    __ beqz($res$$Register, failed);
    -    __ mv(t0, $oldval$$Register);
    -    __ bind(failed);
    +               Assembler::aq /* acquire */, Assembler::rl /* release */, $tmp$$Register);
    +    __ sub(t0, $tmp$$Register, $oldval$$Register);
    +    __ seqz($res$$Register, t0);
         if (barrier_data() != XLoadBarrierElided) {
           Label good;
    -      __ ld(t1, Address(xthread, XThreadLocalData::address_bad_mask_offset()), t1 /* tmp */);
    -      __ andr(t1, t1, t0);
    -      __ beqz(t1, good);
    -      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), t0 /* ref */, t1 /* tmp */);
    +      __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset()));
    +      __ andr(t0, t0, $tmp$$Register);
    +      __ beqz(t0, good);
    +      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), $tmp$$Register /* ref */, $res$$Register /* tmp */);
           __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
                      Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register,
                      true /* result_as_bool */);
    @@ -143,10 +139,10 @@ instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
       ins_pipe(pipe_slow);
     %}
     
    -instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) %{
    +instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
       match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
       predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong);
    -  effect(TEMP_DEF res);
    +  effect(TEMP_DEF res, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -161,7 +157,7 @@ instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n
           __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset()));
           __ andr(t0, t0, $res$$Register);
           __ beqz(t0, good);
    -      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), $res$$Register /* ref */, t0 /* tmp */);
    +      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), $res$$Register /* ref */, $tmp$$Register /* tmp */);
           __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
                      Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register);
           __ bind(good);
    @@ -171,10 +167,10 @@ instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n
       ins_pipe(pipe_slow);
     %}
     
    -instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) %{
    +instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
       match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
       predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong);
    -  effect(TEMP_DEF res);
    +  effect(TEMP_DEF res, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -189,7 +185,7 @@ instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg
           __ ld(t0, Address(xthread, XThreadLocalData::address_bad_mask_offset()));
           __ andr(t0, t0, $res$$Register);
           __ beqz(t0, good);
    -      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), $res$$Register /* ref */, t0 /* tmp */);
    +      x_load_barrier_slow_path(_masm, this, Address($mem$$Register), $res$$Register /* ref */, $tmp$$Register /* tmp */);
           __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
                      Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register);
           __ bind(good);
    @@ -199,10 +195,10 @@ instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg
       ins_pipe(pipe_slow);
     %}
     
    -instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{
    +instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
       match(Set prev (GetAndSetP mem newv));
       predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP_DEF prev, KILL cr);
    +  effect(TEMP_DEF prev, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -210,16 +206,16 @@ instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{
     
       ins_encode %{
         __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -    x_load_barrier(_masm, this, Address(noreg, 0), $prev$$Register, t0 /* tmp */, barrier_data());
    +    x_load_barrier(_masm, this, Address(noreg, 0), $prev$$Register, $tmp$$Register /* tmp */, barrier_data());
       %}
     
       ins_pipe(pipe_serial);
     %}
     
    -instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{
    +instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
       match(Set prev (GetAndSetP mem newv));
       predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() != 0));
    -  effect(TEMP_DEF prev, KILL cr);
    +  effect(TEMP_DEF prev, TEMP tmp);
     
       ins_cost(VOLATILE_REF_COST);
     
    @@ -227,7 +223,7 @@ instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr)
     
       ins_encode %{
         __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -    x_load_barrier(_masm, this, Address(noreg, 0), $prev$$Register, t0 /* tmp */, barrier_data());
    +    x_load_barrier(_masm, this, Address(noreg, 0), $prev$$Register, $tmp$$Register /* tmp */, barrier_data());
       %}
       ins_pipe(pipe_serial);
     %}
    diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad
    index 1429f4ad520..29de8234029 100644
    --- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad
    +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad
    @@ -79,7 +79,7 @@ static void z_load_barrier(MacroAssembler& _masm, const MachNode* node, Address
     
     static void z_store_barrier(MacroAssembler& _masm, const MachNode* node, Address ref_addr, Register rnew_zaddress, Register rnew_zpointer, Register tmp, bool is_atomic) {
       if (node->barrier_data() == ZBarrierElided) {
    -    z_color(_masm, node, rnew_zpointer, rnew_zaddress, t0);
    +    z_color(_masm, node, rnew_zpointer, rnew_zaddress, tmp);
       } else {
         bool is_native = (node->barrier_data() & ZBarrierNative) != 0;
         ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic);
    @@ -90,11 +90,11 @@ static void z_store_barrier(MacroAssembler& _masm, const MachNode* node, Address
     %}
     
     // Load Pointer
    -instruct zLoadP(iRegPNoSp dst, memory mem)
    +instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp)
     %{
       match(Set dst (LoadP mem));
       predicate(UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0);
    -  effect(TEMP dst);
    +  effect(TEMP dst, TEMP tmp);
     
       ins_cost(4 * DEFAULT_COST);
     
    @@ -103,34 +103,35 @@ instruct zLoadP(iRegPNoSp dst, memory mem)
       ins_encode %{
         const Address ref_addr(as_Register($mem$$base), $mem$$disp);
         __ ld($dst$$Register, ref_addr);
    -    z_load_barrier(_masm, this, ref_addr, $dst$$Register, t0);
    +    z_load_barrier(_masm, this, ref_addr, $dst$$Register, $tmp$$Register);
       %}
     
       ins_pipe(iload_reg_mem);
     %}
     
     // Store Pointer
    -instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp, rFlagsReg cr)
    +instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2)
     %{
       predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0);
       match(Set mem (StoreP mem src));
    -  effect(TEMP tmp, KILL cr);
    +  effect(TEMP tmp1, TEMP tmp2);
     
       ins_cost(125); // XXX
       format %{ "sd    $mem, $src\t# ptr" %}
       ins_encode %{
         const Address ref_addr(as_Register($mem$$base), $mem$$disp);
    -    z_store_barrier(_masm, this, ref_addr, $src$$Register, $tmp$$Register, t1, false /* is_atomic */);
    -    __ sd($tmp$$Register, ref_addr);
    +    z_store_barrier(_masm, this, ref_addr, $src$$Register, $tmp1$$Register, $tmp2$$Register, false /* is_atomic */);
    +    __ sd($tmp1$$Register, ref_addr);
       %}
       ins_pipe(pipe_serial);
     %}
     
    -instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{
    +instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval,
    +                          iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
       match(Set res (CompareAndSwapP mem (Binary oldval newval)));
       match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
       predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP oldval_tmp, TEMP newval_tmp, KILL cr, TEMP_DEF res);
    +  effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -140,19 +141,20 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva
       ins_encode %{
         guarantee($mem$$disp == 0, "impossible encoding");
         Address ref_addr($mem$$Register);
    -    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, t0);
    -    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, t1, true /* is_atomic */);
    +    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register);
    +    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */);
         __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, true /* result_as_bool */);
       %}
     
       ins_pipe(pipe_slow);
     %}
     
    -instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{
    +instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval,
    +                             iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
       match(Set res (CompareAndSwapP mem (Binary oldval newval)));
       match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
       predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP oldval_tmp, TEMP newval_tmp, KILL cr, TEMP_DEF res);
    +  effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -162,18 +164,19 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
       ins_encode %{
         guarantee($mem$$disp == 0, "impossible encoding");
         Address ref_addr($mem$$Register);
    -    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, t0);
    -    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, t1, true /* is_atomic */);
    +    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register);
    +    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */);
         __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, true /* result_as_bool */);
       %}
     
       ins_pipe(pipe_slow);
     %}
     
    -instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{
    +instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval,
    +                              iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
       match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
       predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP oldval_tmp, TEMP newval_tmp, KILL cr, TEMP_DEF res);
    +  effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -182,8 +185,8 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n
       ins_encode %{
         guarantee($mem$$disp == 0, "impossible encoding");
         Address ref_addr($mem$$Register);
    -    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, t0);
    -    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, t1, true /* is_atomic */);
    +    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register);
    +    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */);
         __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register);
         z_uncolor(_masm, this, $res$$Register);
       %}
    @@ -191,10 +194,11 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n
       ins_pipe(pipe_slow);
     %}
     
    -instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{
    +instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval,
    +                                 iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
       match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
       predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP oldval_tmp, TEMP newval_tmp, KILL cr, TEMP_DEF res);
    +  effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
    @@ -203,8 +207,8 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg
       ins_encode %{
         guarantee($mem$$disp == 0, "impossible encoding");
         Address ref_addr($mem$$Register);
    -    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, t0);
    -    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, t1, true /* is_atomic */);
    +    z_color(_masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register);
    +    z_store_barrier(_masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */);
         __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register);
         z_uncolor(_masm, this, $res$$Register);
       %}
    @@ -212,17 +216,17 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg
       ins_pipe(pipe_slow);
     %}
     
    -instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{
    +instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
       match(Set prev (GetAndSetP mem newv));
       predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP_DEF prev, KILL cr);
    +  effect(TEMP_DEF prev, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
       format %{ "atomic_xchg  $prev, $newv, [$mem], #@zGetAndSetP" %}
     
       ins_encode %{
    -    z_store_barrier(_masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, t1, true /* is_atomic */);
    +    z_store_barrier(_masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, $tmp$$Register, true /* is_atomic */);
         __ atomic_xchg($prev$$Register, $prev$$Register, $mem$$Register);
         z_uncolor(_masm, this, $prev$$Register);
       %}
    @@ -230,17 +234,17 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{
       ins_pipe(pipe_serial);
     %}
     
    -instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{
    +instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
       match(Set prev (GetAndSetP mem newv));
       predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
    -  effect(TEMP_DEF prev, KILL cr);
    +  effect(TEMP_DEF prev, TEMP tmp);
     
       ins_cost(2 * VOLATILE_REF_COST);
     
       format %{ "atomic_xchg_acq  $prev, $newv, [$mem], #@zGetAndSetPAcq" %}
     
       ins_encode %{
    -    z_store_barrier(_masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, t1, true /* is_atomic */);
    +    z_store_barrier(_masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, $tmp$$Register, true /* is_atomic */);
         __ atomic_xchgal($prev$$Register, $prev$$Register, $mem$$Register);
         z_uncolor(_masm, this, $prev$$Register);
       %}
    diff --git a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp
    index f40ffbeefa7..e368bbdc914 100644
    --- a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp
    @@ -50,6 +50,10 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
     
     #define USE_POINTERS_TO_REGISTER_IMPL_ARRAY
     
    +// The expected size in bytes of a cache line.
     #define DEFAULT_CACHE_LINE_SIZE 64
     
    +// The default padding size for data structures to avoid false sharing.
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
    +
     #endif // CPU_RISCV_GLOBALDEFINITIONS_RISCV_HPP
    diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp
    index 8824b0e1f93..aa95cebec14 100644
    --- a/src/hotspot/cpu/riscv/globals_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp
    @@ -105,6 +105,7 @@ define_pd_global(intx, InlineSmallCode,          1000);
       product(bool, UseZba, false, "Use Zba instructions")                           \
       product(bool, UseZbb, false, "Use Zbb instructions")                           \
       product(bool, UseZbs, false, "Use Zbs instructions")                           \
    +  product(bool, UseZacas, false, EXPERIMENTAL, "Use Zacas instructions")         \
       product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions")       \
       product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions")       \
       product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions")       \
    @@ -112,6 +113,8 @@ define_pd_global(intx, InlineSmallCode,          1000);
       product(bool, UseZtso, false, EXPERIMENTAL, "Assume Ztso memory model")        \
       product(bool, UseZihintpause, false, EXPERIMENTAL,                             \
               "Use Zihintpause instructions")                                        \
    +  product(bool, UseZvkn, false, EXPERIMENTAL,                                    \
    +          "Use Zvkn group extension, Zvkned, Zvknhb, Zvkb, Zvkt")                \
       product(bool, UseRVVForBigIntegerShiftIntrinsics, true,                        \
               "Use RVV instructions for left/right shift of BigInteger")
     
    diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
    index 030a6f0fe96..19d665bd421 100644
    --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
    @@ -777,7 +777,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
           assert(lock_offset == 0,
                  "displached header must be first word in BasicObjectLock");
     
    -      cmpxchg_obj_header(swap_reg, lock_reg, obj_reg, t0, count, /*fallthrough*/nullptr);
    +      cmpxchg_obj_header(swap_reg, lock_reg, obj_reg, tmp, count, /*fallthrough*/nullptr);
     
           // Test if the oopMark is an obvious stack pointer, i.e.,
           //  1) (mark & 7) == 0, and
    @@ -891,7 +891,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg)
           beqz(header_reg, count);
     
           // Atomic swap back the old header
    -      cmpxchg_obj_header(swap_reg, header_reg, obj_reg, t0, count, /*fallthrough*/nullptr);
    +      cmpxchg_obj_header(swap_reg, header_reg, obj_reg, tmp_reg, count, /*fallthrough*/nullptr);
         }
     
         // Call the runtime routine for slow case.
    diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
    index 3acc010ff85..ce336c16aa7 100644
    --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
      * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    @@ -2725,27 +2725,36 @@ void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acqui
     
     void MacroAssembler::cmpxchgptr(Register oldv, Register newv, Register addr, Register tmp,
                                     Label &succeed, Label *fail) {
    -  assert_different_registers(addr, tmp);
    -  assert_different_registers(newv, tmp);
    -  assert_different_registers(oldv, tmp);
    +  assert_different_registers(addr, tmp, t0);
    +  assert_different_registers(newv, tmp, t0);
    +  assert_different_registers(oldv, tmp, t0);
     
       // oldv holds comparison value
       // newv holds value to write in exchange
       // addr identifies memory word to compare against/update
    -  Label retry_load, nope;
    -  bind(retry_load);
    -  // Load reserved from the memory location
    -  load_reserved(tmp, addr, int64, Assembler::aqrl);
    -  // Fail and exit if it is not what we expect
    -  bne(tmp, oldv, nope);
    -  // If the store conditional succeeds, tmp will be zero
    -  store_conditional(tmp, newv, addr, int64, Assembler::rl);
    -  beqz(tmp, succeed);
    -  // Retry only when the store conditional failed
    -  j(retry_load);
    -
    -  bind(nope);
    +  if (UseZacas) {
    +    mv(tmp, oldv);
    +    atomic_cas(tmp, newv, addr, Assembler::int64, Assembler::aq, Assembler::rl);
    +    beq(tmp, oldv, succeed);
    +  } else {
    +    Label retry_load, nope;
    +    bind(retry_load);
    +    // Load reserved from the memory location
    +    load_reserved(tmp, addr, int64, Assembler::aqrl);
    +    // Fail and exit if it is not what we expect
    +    bne(tmp, oldv, nope);
    +    // If the store conditional succeeds, tmp will be zero
    +    store_conditional(tmp, newv, addr, int64, Assembler::rl);
    +    beqz(tmp, succeed);
    +    // Retry only when the store conditional failed
    +    j(retry_load);
    +
    +    bind(nope);
    +  }
    +
    +  // neither amocas nor lr/sc have an implied barrier in the failing case
       membar(AnyAny);
    +
       mv(oldv, tmp);
       if (fail != nullptr) {
         j(*fail);
    @@ -2771,7 +2780,7 @@ void MacroAssembler::load_reserved(Register dst,
           break;
         case uint32:
           lr_w(dst, addr, acquire);
    -      zero_extend(t0, t0, 32);
    +      zero_extend(dst, dst, 32);
           break;
         default:
           ShouldNotReachHere();
    @@ -2819,7 +2828,7 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte
       }
       sll(mask, mask, shift);
     
    -  xori(not_mask, mask, -1);
    +  notr(not_mask, mask);
     
       sll(expected, expected, shift);
       andr(expected, expected, mask);
    @@ -2829,7 +2838,7 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte
     }
     
     // cmpxchg_narrow_value will kill t0, t1, expected, new_val and tmps.
    -// It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w,
    +// It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w or amocas.w,
     // which are forced to work with 4-byte aligned address.
     void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
                                               Register new_val,
    @@ -2844,14 +2853,29 @@ void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
       Label retry, fail, done;
     
       bind(retry);
    -  lr_w(old, aligned_addr, acquire);
    -  andr(tmp, old, mask);
    -  bne(tmp, expected, fail);
     
    -  andr(tmp, old, not_mask);
    -  orr(tmp, tmp, new_val);
    -  sc_w(tmp, tmp, aligned_addr, release);
    -  bnez(tmp, retry);
    +  if (UseZacas) {
    +    lw(old, aligned_addr);
    +
    +    // if old & mask != expected
    +    andr(tmp, old, mask);
    +    bne(tmp, expected, fail);
    +
    +    andr(tmp, old, not_mask);
    +    orr(tmp, tmp, new_val);
    +
    +    atomic_cas(old, tmp, aligned_addr, operand_size::int32, acquire, release);
    +    bne(tmp, old, retry);
    +  } else {
    +    lr_w(old, aligned_addr, acquire);
    +    andr(tmp, old, mask);
    +    bne(tmp, expected, fail);
    +
    +    andr(tmp, old, not_mask);
    +    orr(tmp, tmp, new_val);
    +    sc_w(tmp, tmp, aligned_addr, release);
    +    bnez(tmp, retry);
    +  }
     
       if (result_as_bool) {
         mv(result, 1);
    @@ -2891,14 +2915,28 @@ void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected,
     
       Label fail, done;
     
    -  lr_w(old, aligned_addr, acquire);
    -  andr(tmp, old, mask);
    -  bne(tmp, expected, fail);
    +  if (UseZacas) {
    +    lw(old, aligned_addr);
    +
    +    // if old & mask != expected
    +    andr(tmp, old, mask);
    +    bne(tmp, expected, fail);
    +
    +    andr(tmp, old, not_mask);
    +    orr(tmp, tmp, new_val);
    +
    +    atomic_cas(tmp, new_val, addr, operand_size::int32, acquire, release);
    +    bne(tmp, old, fail);
    +  } else {
    +    lr_w(old, aligned_addr, acquire);
    +    andr(tmp, old, mask);
    +    bne(tmp, expected, fail);
     
    -  andr(tmp, old, not_mask);
    -  orr(tmp, tmp, new_val);
    -  sc_w(tmp, tmp, aligned_addr, release);
    -  bnez(tmp, fail);
    +    andr(tmp, old, not_mask);
    +    orr(tmp, tmp, new_val);
    +    sc_w(tmp, tmp, aligned_addr, release);
    +    bnez(tmp, fail);
    +  }
     
       // Success
       mv(result, 1);
    @@ -2921,6 +2959,19 @@ void MacroAssembler::cmpxchg(Register addr, Register expected,
       assert_different_registers(expected, t0);
       assert_different_registers(new_val, t0);
     
    +  if (UseZacas) {
    +    if (result_as_bool) {
    +      mv(t0, expected);
    +      atomic_cas(t0, new_val, addr, size, acquire, release);
    +      xorr(t0, t0, expected);
    +      seqz(result, t0);
    +    } else {
    +      mv(result, expected);
    +      atomic_cas(result, new_val, addr, size, acquire, release);
    +    }
    +    return;
    +  }
    +
       Label retry_load, done, ne_done;
       bind(retry_load);
       load_reserved(t0, addr, size, acquire);
    @@ -2952,6 +3003,11 @@ void MacroAssembler::cmpxchg_weak(Register addr, Register expected,
                                       enum operand_size size,
                                       Assembler::Aqrl acquire, Assembler::Aqrl release,
                                       Register result) {
    +  if (UseZacas) {
    +    cmpxchg(addr, expected, new_val, size, acquire, release, result, true);
    +    return;
    +  }
    +
       assert_different_registers(addr, t0);
       assert_different_registers(expected, t0);
       assert_different_registers(new_val, t0);
    @@ -3018,6 +3074,89 @@ ATOMIC_XCHGU(xchgalwu, xchgalw)
     
     #undef ATOMIC_XCHGU
     
    +#define ATOMIC_CAS(OP, AOP, ACQUIRE, RELEASE)                                        \
    +void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) {      \
    +  assert(UseZacas, "invariant");                                                     \
    +  prev = prev->is_valid() ? prev : zr;                                               \
    +  AOP(prev, addr, newv, (Assembler::Aqrl)(ACQUIRE | RELEASE));                       \
    +  return;                                                                            \
    +}
    +
    +ATOMIC_CAS(cas, amocas_d, Assembler::relaxed, Assembler::relaxed)
    +ATOMIC_CAS(casw, amocas_w, Assembler::relaxed, Assembler::relaxed)
    +ATOMIC_CAS(casl, amocas_d, Assembler::relaxed, Assembler::rl)
    +ATOMIC_CAS(caslw, amocas_w, Assembler::relaxed, Assembler::rl)
    +ATOMIC_CAS(casal, amocas_d, Assembler::aq, Assembler::rl)
    +ATOMIC_CAS(casalw, amocas_w, Assembler::aq, Assembler::rl)
    +
    +#undef ATOMIC_CAS
    +
    +#define ATOMIC_CASU(OP1, OP2)                                                        \
    +void MacroAssembler::atomic_##OP1(Register prev, Register newv, Register addr) {     \
    +  atomic_##OP2(prev, newv, addr);                                                    \
    +  zero_extend(prev, prev, 32);                                                       \
    +  return;                                                                            \
    +}
    +
    +ATOMIC_CASU(caswu, casw)
    +ATOMIC_CASU(caslwu, caslw)
    +ATOMIC_CASU(casalwu, casalw)
    +
    +#undef ATOMIC_CASU
    +
    +void MacroAssembler::atomic_cas(
    +    Register prev, Register newv, Register addr, enum operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release) {
    +  switch (size) {
    +    case int64:
    +      switch ((Assembler::Aqrl)(acquire | release)) {
    +        case Assembler::relaxed:
    +          atomic_cas(prev, newv, addr);
    +          break;
    +        case Assembler::rl:
    +          atomic_casl(prev, newv, addr);
    +          break;
    +        case Assembler::aqrl:
    +          atomic_casal(prev, newv, addr);
    +          break;
    +        default:
    +          ShouldNotReachHere();
    +      }
    +      break;
    +    case int32:
    +      switch ((Assembler::Aqrl)(acquire | release)) {
    +        case Assembler::relaxed:
    +          atomic_casw(prev, newv, addr);
    +          break;
    +        case Assembler::rl:
    +          atomic_caslw(prev, newv, addr);
    +          break;
    +        case Assembler::aqrl:
    +          atomic_casalw(prev, newv, addr);
    +          break;
    +        default:
    +          ShouldNotReachHere();
    +      }
    +      break;
    +    case uint32:
    +      switch ((Assembler::Aqrl)(acquire | release)) {
    +        case Assembler::relaxed:
    +          atomic_caswu(prev, newv, addr);
    +          break;
    +        case Assembler::rl:
    +          atomic_caslwu(prev, newv, addr);
    +          break;
    +        case Assembler::aqrl:
    +          atomic_casalwu(prev, newv, addr);
    +          break;
    +        default:
    +          ShouldNotReachHere();
    +      }
    +      break;
    +    default:
    +      ShouldNotReachHere();
    +  }
    +}
    +
     void MacroAssembler::far_jump(const Address &entry, Register tmp) {
       assert(ReservedCodeCacheSize < 4*G, "branch out of range");
       assert(CodeCache::find_blob(entry.target()) != nullptr,
    @@ -4342,6 +4481,57 @@ void MacroAssembler::zero_dcache_blocks(Register base, Register cnt, Register tm
       bge(cnt, tmp1, loop);
     }
     
    +// java.lang.Math.round(float a)
    +// Returns the closest int to the argument, with ties rounding to positive infinity.
    +void MacroAssembler::java_round_float(Register dst, FloatRegister src, FloatRegister ftmp) {
    +  // this instructions calling sequence provides performance improvement on all tested devices;
    +  // don't change it without re-verification
    +  Label done;
    +  mv(t0, jint_cast(0.5f));
    +  fmv_w_x(ftmp, t0);
    +
    +  // dst = 0 if NaN
    +  feq_s(t0, src, src); // replacing fclass with feq as performance optimization
    +  mv(dst, zr);
    +  beqz(t0, done);
    +
    +  // dst = (src + 0.5f) rounded down towards negative infinity
    +  //   Adding 0.5f to some floats exceeds the precision limits for a float and rounding takes place.
    +  //   RDN is required for fadd_s, RNE gives incorrect results:
    +  //     --------------------------------------------------------------------
    +  //     fadd.s rne (src + 0.5f): src = 8388609.000000  ftmp = 8388610.000000
    +  //     fcvt.w.s rdn: ftmp = 8388610.000000 dst = 8388610
    +  //     --------------------------------------------------------------------
    +  //     fadd.s rdn (src + 0.5f): src = 8388609.000000  ftmp = 8388609.000000
    +  //     fcvt.w.s rdn: ftmp = 8388609.000000 dst = 8388609
    +  //     --------------------------------------------------------------------
    +  fadd_s(ftmp, src, ftmp, RoundingMode::rdn);
    +  fcvt_w_s(dst, ftmp, RoundingMode::rdn);
    +
    +  bind(done);
    +}
    +
    +// java.lang.Math.round(double a)
    +// Returns the closest long to the argument, with ties rounding to positive infinity.
    +void MacroAssembler::java_round_double(Register dst, FloatRegister src, FloatRegister ftmp) {
    +  // this instructions calling sequence provides performance improvement on all tested devices;
    +  // don't change it without re-verification
    +  Label done;
    +  mv(t0, julong_cast(0.5));
    +  fmv_d_x(ftmp, t0);
    +
    +  // dst = 0 if NaN
    +  feq_d(t0, src, src); // replacing fclass with feq as performance optimization
    +  mv(dst, zr);
    +  beqz(t0, done);
    +
    +  // dst = (src + 0.5) rounded down towards negative infinity
    +  fadd_d(ftmp, src, ftmp, RoundingMode::rdn); // RDN is required here otherwise some inputs produce incorrect results
    +  fcvt_l_d(dst, ftmp, RoundingMode::rdn);
    +
    +  bind(done);
    +}
    +
     #define FCVT_SAFE(FLOATCVT, FLOATSIG)                                                     \
     void MacroAssembler::FLOATCVT##_safe(Register dst, FloatRegister src, Register tmp) {     \
       Label done;                                                                             \
    @@ -4488,41 +4678,54 @@ void MacroAssembler::shadd(Register Rd, Register Rs1, Register Rs2, Register tmp
     }
     
     void MacroAssembler::zero_extend(Register dst, Register src, int bits) {
    -  if (UseZba && bits == 32) {
    -    zext_w(dst, src);
    -    return;
    -  }
    -
    -  if (UseZbb && bits == 16) {
    -    zext_h(dst, src);
    -    return;
    -  }
    -
    -  if (bits == 8) {
    -    zext_b(dst, src);
    -  } else {
    -    slli(dst, src, XLEN - bits);
    -    srli(dst, dst, XLEN - bits);
    +  switch (bits) {
    +    case 32:
    +      if (UseZba) {
    +        zext_w(dst, src);
    +        return;
    +      }
    +      break;
    +    case 16:
    +      if (UseZbb) {
    +        zext_h(dst, src);
    +        return;
    +      }
    +      break;
    +    case 8:
    +      if (UseZbb) {
    +        zext_b(dst, src);
    +        return;
    +      }
    +      break;
    +    default:
    +      break;
       }
    +  slli(dst, src, XLEN - bits);
    +  srli(dst, dst, XLEN - bits);
     }
     
     void MacroAssembler::sign_extend(Register dst, Register src, int bits) {
    -  if (UseZbb) {
    -    if (bits == 8) {
    -      sext_b(dst, src);
    -      return;
    -    } else if (bits == 16) {
    -      sext_h(dst, src);
    +  switch (bits) {
    +    case 32:
    +      sext_w(dst, src);
           return;
    -    }
    -  }
    -
    -  if (bits == 32) {
    -    sext_w(dst, src);
    -  } else {
    -    slli(dst, src, XLEN - bits);
    -    srai(dst, dst, XLEN - bits);
    +    case 16:
    +      if (UseZbb) {
    +        sext_h(dst, src);
    +        return;
    +      }
    +      break;
    +    case 8:
    +      if (UseZbb) {
    +        sext_b(dst, src);
    +        return;
    +      }
    +      break;
    +    default:
    +      break;
       }
    +  slli(dst, src, XLEN - bits);
    +  srai(dst, dst, XLEN - bits);
     }
     
     void MacroAssembler::cmp_x2i(Register dst, Register src1, Register src2,
    @@ -4701,9 +4904,9 @@ void MacroAssembler::object_move(OopMap* map,
     
     // A float arg may have to do float reg int reg conversion
     void MacroAssembler::float_move(VMRegPair src, VMRegPair dst, Register tmp) {
    -  assert(src.first()->is_stack() && dst.first()->is_stack() ||
    -         src.first()->is_reg() && dst.first()->is_reg() ||
    -         src.first()->is_stack() && dst.first()->is_reg(), "Unexpected error");
    +  assert((src.first()->is_stack() && dst.first()->is_stack()) ||
    +         (src.first()->is_reg() && dst.first()->is_reg()) ||
    +         (src.first()->is_stack() && dst.first()->is_reg()), "Unexpected error");
       if (src.first()->is_stack()) {
         if (dst.first()->is_stack()) {
           lwu(tmp, Address(fp, reg2offset_in(src.first())));
    @@ -4745,9 +4948,9 @@ void MacroAssembler::long_move(VMRegPair src, VMRegPair dst, Register tmp) {
     
     // A double move
     void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) {
    -  assert(src.first()->is_stack() && dst.first()->is_stack() ||
    -         src.first()->is_reg() && dst.first()->is_reg() ||
    -         src.first()->is_stack() && dst.first()->is_reg(), "Unexpected error");
    +  assert((src.first()->is_stack() && dst.first()->is_stack()) ||
    +         (src.first()->is_reg() && dst.first()->is_reg()) ||
    +         (src.first()->is_stack() && dst.first()->is_reg()), "Unexpected error");
       if (src.first()->is_stack()) {
         if (dst.first()->is_stack()) {
           ld(tmp, Address(fp, reg2offset_in(src.first())));
    diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
    index 3b110cd3e28..d283654e6e1 100644
    --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
    @@ -473,7 +473,11 @@ class MacroAssembler: public Assembler {
       }
     
       inline void notr(Register Rd, Register Rs) {
    -    xori(Rd, Rs, -1);
    +    if (do_compress_zcb(Rd, Rs) && (Rd == Rs)) {
    +      c_not(Rd);
    +    } else {
    +      xori(Rd, Rs, -1);
    +    }
       }
     
       inline void neg(Register Rd, Register Rs) {
    @@ -489,7 +493,11 @@ class MacroAssembler: public Assembler {
       }
     
       inline void zext_b(Register Rd, Register Rs) {
    -    andi(Rd, Rs, 0xFF);
    +    if (do_compress_zcb(Rd, Rs) && (Rd == Rs)) {
    +      c_zext_b(Rd);
    +    } else {
    +      andi(Rd, Rs, 0xFF);
    +    }
       }
     
       inline void seqz(Register Rd, Register Rs) {
    @@ -511,7 +519,12 @@ class MacroAssembler: public Assembler {
       // Bit-manipulation extension pseudo instructions
       // zero extend word
       inline void zext_w(Register Rd, Register Rs) {
    -    add_uw(Rd, Rs, zr);
    +    assert(UseZba, "must be");
    +    if (do_compress_zcb(Rd, Rs) && (Rd == Rs)) {
    +      c_zext_w(Rd);
    +    } else {
    +      add_uw(Rd, Rs, zr);
    +    }
       }
     
       // Floating-point data-processing pseudo instructions
    @@ -1063,6 +1076,19 @@ class MacroAssembler: public Assembler {
       void atomic_xchgwu(Register prev, Register newv, Register addr);
       void atomic_xchgalwu(Register prev, Register newv, Register addr);
     
    +  void atomic_cas(Register prev, Register newv, Register addr);
    +  void atomic_casw(Register prev, Register newv, Register addr);
    +  void atomic_casl(Register prev, Register newv, Register addr);
    +  void atomic_caslw(Register prev, Register newv, Register addr);
    +  void atomic_casal(Register prev, Register newv, Register addr);
    +  void atomic_casalw(Register prev, Register newv, Register addr);
    +  void atomic_caswu(Register prev, Register newv, Register addr);
    +  void atomic_caslwu(Register prev, Register newv, Register addr);
    +  void atomic_casalwu(Register prev, Register newv, Register addr);
    +
    +  void atomic_cas(Register prev, Register newv, Register addr, enum operand_size size,
    +              Assembler::Aqrl acquire = Assembler::relaxed, Assembler::Aqrl release = Assembler::relaxed);
    +
       // Emit a far call/jump. Only invalidates the tmp register which
       // is used to keep the entry address for jalr.
       // The address must be inside the code cache.
    @@ -1252,6 +1278,9 @@ class MacroAssembler: public Assembler {
       void fcvt_w_d_safe(Register dst, FloatRegister src, Register tmp = t0);
       void fcvt_l_d_safe(Register dst, FloatRegister src, Register tmp = t0);
     
    +  void java_round_float(Register dst, FloatRegister src, FloatRegister ftmp);
    +  void java_round_double(Register dst, FloatRegister src, FloatRegister ftmp);
    +
       // vector load/store unit-stride instructions
       void vlex_v(VectorRegister vd, Register base, Assembler::SEW sew, VectorMask vm = unmasked) {
         switch (sew) {
    @@ -1345,6 +1374,16 @@ class MacroAssembler: public Assembler {
         vmfle_vv(vd, vs1, vs2, vm);
       }
     
    +  inline void vmsltu_vi(VectorRegister Vd, VectorRegister Vs2, uint32_t imm, VectorMask vm = unmasked) {
    +    guarantee(imm >= 1 && imm <= 16, "imm is invalid");
    +    vmsleu_vi(Vd, Vs2, imm-1, vm);
    +  }
    +
    +  inline void vmsgeu_vi(VectorRegister Vd, VectorRegister Vs2, uint32_t imm, VectorMask vm = unmasked) {
    +    guarantee(imm >= 1 && imm <= 16, "imm is invalid");
    +    vmsgtu_vi(Vd, Vs2, imm-1, vm);
    +  }
    +
       // Copy mask register
       inline void vmmv_m(VectorRegister vd, VectorRegister vs) {
         vmand_mm(vd, vs, vs);
    @@ -1360,6 +1399,10 @@ class MacroAssembler: public Assembler {
         vmxnor_mm(vd, vd, vd);
       }
     
    +  inline void vnot_v(VectorRegister Vd, VectorRegister Vs, VectorMask vm = unmasked) {
    +    vxor_vi(Vd, Vs, -1, vm);
    +  }
    +
       static const int zero_words_block_size;
     
       void cast_primitive_type(BasicType type, Register Rt) {
    diff --git a/src/hotspot/cpu/riscv/matcher_riscv.hpp b/src/hotspot/cpu/riscv/matcher_riscv.hpp
    index 1da8f003122..08914d4d834 100644
    --- a/src/hotspot/cpu/riscv/matcher_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/matcher_riscv.hpp
    @@ -192,4 +192,9 @@
         }
       }
     
    +  // Is SIMD sort supported for this CPU?
    +  static bool supports_simd_sort(BasicType bt) {
    +    return false;
    +  }
    +
     #endif // CPU_RISCV_MATCHER_RISCV_HPP
    diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
    index 2b2e5606c81..c29ac1a04fa 100644
    --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
    @@ -451,16 +451,27 @@ void NativePostCallNop::make_deopt() {
       NativeDeoptInstruction::insert(addr_at(0));
     }
     
    -int NativePostCallNop::displacement() const {
    +bool NativePostCallNop::decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
       // Discard the high 32 bits
    -  return (int)(intptr_t)MacroAssembler::get_target_of_li32(addr_at(4));
    +  int32_t data = (int32_t)(intptr_t)MacroAssembler::get_target_of_li32(addr_at(4));
    +  if (data == 0) {
    +    return false; // no information encoded
    +  }
    +  cb_offset = (data & 0xffffff);
    +  oopmap_slot = (data >> 24) & 0xff;
    +  return true; // decoding succeeded
     }
     
    -void NativePostCallNop::patch(jint diff) {
    -  assert(diff != 0, "must be");
    +bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
    +  if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) {
    +    return false; // cannot encode
    +  }
    +  int32_t data = (oopmap_slot << 24) | cb_offset;
    +  assert(data != 0, "must be");
       assert(is_lui_to_zr_at(addr_at(4)) && is_addiw_to_zr_at(addr_at(8)), "must be");
     
    -  MacroAssembler::patch_imm_in_li32(addr_at(4), diff);
    +  MacroAssembler::patch_imm_in_li32(addr_at(4), data);
    +  return true; // successfully encoded
     }
     
     void NativeDeoptInstruction::verify() {
    diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
    index 3c6ec1cf588..48bbb2b3b18 100644
    --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
    @@ -591,8 +591,8 @@ class NativePostCallNop: public NativeInstruction {
         // an addiw as well.
         return is_nop() && is_lui_to_zr_at(addr_at(4));
       }
    -  int displacement() const;
    -  void patch(jint diff);
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const;
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset);
       void make_deopt();
     };
     
    diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad
    index 1096ca80043..7e1291f49d7 100644
    --- a/src/hotspot/cpu/riscv/riscv.ad
    +++ b/src/hotspot/cpu/riscv/riscv.ad
    @@ -1001,6 +1001,7 @@ definitions %{
       int_def LOAD_COST            (  300,  3 * DEFAULT_COST);          // load, fpload
       int_def STORE_COST           (  100,  1 * DEFAULT_COST);          // store, fpstore
       int_def XFER_COST            (  300,  3 * DEFAULT_COST);          // mfc, mtc, fcvt, fmove, fcmp
    +  int_def FMVX_COST            (  100,  1 * DEFAULT_COST);          // shuffles with no conversion
       int_def BRANCH_COST          (  200,  2 * DEFAULT_COST);          // branch, jmp, call
       int_def IMUL_COST            ( 1000, 10 * DEFAULT_COST);          // imul
       int_def IDIVSI_COST          ( 3400, 34 * DEFAULT_COST);          // idivsi
    @@ -8417,6 +8418,34 @@ instruct convN2I(iRegINoSp dst, iRegN src)
       ins_pipe(ialu_reg);
     %}
     
    +instruct round_double_reg(iRegLNoSp dst, fRegD src, fRegD ftmp) %{
    +  match(Set dst (RoundD src));
    +
    +  ins_cost(XFER_COST + BRANCH_COST);
    +  effect(TEMP ftmp);
    +  format %{ "java_round_double $dst, $src\t#@round_double_reg" %}
    +
    +  ins_encode %{
    +    __ java_round_double($dst$$Register, as_FloatRegister($src$$reg), as_FloatRegister($ftmp$$reg));
    +  %}
    +
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct round_float_reg(iRegINoSp dst, fRegF src, fRegF ftmp) %{
    +  match(Set dst (RoundF src));
    +
    +  ins_cost(XFER_COST + BRANCH_COST);
    +  effect(TEMP ftmp);
    +  format %{ "java_round_float $dst, $src\t#@round_float_reg" %}
    +
    +  ins_encode %{
    +    __ java_round_float($dst$$Register, as_FloatRegister($src$$reg), as_FloatRegister($ftmp$$reg));
    +  %}
    +
    +  ins_pipe(pipe_slow);
    +%}
    +
     // Convert oop pointer into compressed form
     instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{
       match(Set dst (EncodeP src));
    @@ -8646,7 +8675,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, fRegF src) %{
     
       effect(DEF dst, USE src);
     
    -  ins_cost(XFER_COST);
    +  ins_cost(FMVX_COST);
     
       format %{ "fmv.x.w  $dst, $src\t#@MoveF2I_reg_reg" %}
     
    @@ -8664,7 +8693,7 @@ instruct MoveI2F_reg_reg(fRegF dst, iRegI src) %{
     
       effect(DEF dst, USE src);
     
    -  ins_cost(XFER_COST);
    +  ins_cost(FMVX_COST);
     
       format %{ "fmv.w.x  $dst, $src\t#@MoveI2F_reg_reg" %}
     
    @@ -8682,7 +8711,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, fRegD src) %{
     
       effect(DEF dst, USE src);
     
    -  ins_cost(XFER_COST);
    +  ins_cost(FMVX_COST);
     
       format %{ "fmv.x.d $dst, $src\t#@MoveD2L_reg_reg" %}
     
    @@ -8700,7 +8729,7 @@ instruct MoveL2D_reg_reg(fRegD dst, iRegL src) %{
     
       effect(DEF dst, USE src);
     
    -  ins_cost(XFER_COST);
    +  ins_cost(FMVX_COST);
     
       format %{ "fmv.d.x  $dst, $src\t#@MoveL2D_reg_reg" %}
     
    @@ -10371,6 +10400,26 @@ instruct array_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result,
       ins_pipe(pipe_class_memory);
     %}
     
    +// fast ArraysSupport.vectorizedHashCode
    +instruct arrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI basic_type,
    +                         iRegLNoSp tmp1, iRegLNoSp tmp2,
    +                         iRegLNoSp tmp3, iRegLNoSp tmp4,
    +                         iRegLNoSp tmp5, iRegLNoSp tmp6, rFlagsReg cr)
    +%{
    +  match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type)));
    +  effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6,
    +         USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr);
    +
    +  format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result   // KILL all" %}
    +  ins_encode %{
    +    __ arrays_hashcode($ary$$Register, $cnt$$Register, $result$$Register,
    +                       $tmp1$$Register, $tmp2$$Register, $tmp3$$Register,
    +                       $tmp4$$Register, $tmp5$$Register, $tmp6$$Register,
    +                       (BasicType)$basic_type$$constant);
    +  %}
    +  ins_pipe(pipe_class_memory);
    +%}
    +
     // ============================================================================
     // Safepoint Instructions
     
    diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
    index 36430e126f9..01fe307bc27 100644
    --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
    @@ -266,7 +266,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
     
       uint int_args = 0;
       uint fp_args = 0;
    -  uint stk_args = 0; // inc by 2 each time
    +  uint stk_args = 0;
     
       for (int i = 0; i < total_args_passed; i++) {
         switch (sig_bt[i]) {
    @@ -278,8 +278,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
             if (int_args < Argument::n_int_register_parameters_j) {
               regs[i].set1(INT_ArgReg[int_args++]->as_VMReg());
             } else {
    +          stk_args = align_up(stk_args, 2);
               regs[i].set1(VMRegImpl::stack2reg(stk_args));
    -          stk_args += 2;
    +          stk_args += 1;
             }
             break;
           case T_VOID:
    @@ -295,6 +296,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
             if (int_args < Argument::n_int_register_parameters_j) {
               regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
             } else {
    +          stk_args = align_up(stk_args, 2);
               regs[i].set2(VMRegImpl::stack2reg(stk_args));
               stk_args += 2;
             }
    @@ -303,8 +305,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
             if (fp_args < Argument::n_float_register_parameters_j) {
               regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg());
             } else {
    +          stk_args = align_up(stk_args, 2);
               regs[i].set1(VMRegImpl::stack2reg(stk_args));
    -          stk_args += 2;
    +          stk_args += 1;
             }
             break;
           case T_DOUBLE:
    @@ -312,6 +315,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
             if (fp_args < Argument::n_float_register_parameters_j) {
               regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg());
             } else {
    +          stk_args = align_up(stk_args, 2);
               regs[i].set2(VMRegImpl::stack2reg(stk_args));
               stk_args += 2;
             }
    @@ -321,7 +325,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
         }
       }
     
    -  return align_up(stk_args, 2);
    +  return stk_args;
     }
     
     // Patch the callers callsite with entry to compiled code if it exists.
    @@ -1675,7 +1679,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
           __ sd(swap_reg, Address(lock_reg, mark_word_offset));
     
           // src -> dest if dest == x10 else x10 <- dest
    -      __ cmpxchg_obj_header(x10, lock_reg, obj_reg, t0, count, /*fallthrough*/nullptr);
    +      __ cmpxchg_obj_header(x10, lock_reg, obj_reg, lock_tmp, count, /*fallthrough*/nullptr);
     
           // Test if the oopMark is an obvious stack pointer, i.e.,
           //  1) (mark & 3) == 0, and
    @@ -1815,7 +1819,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
     
           // Atomic swap old header if oop still contains the stack lock
           Label count;
    -      __ cmpxchg_obj_header(x10, old_hdr, obj_reg, t0, count, &slow_path_unlock);
    +      __ cmpxchg_obj_header(x10, old_hdr, obj_reg, lock_tmp, count, &slow_path_unlock);
           __ bind(count);
           __ decrement(Address(xthread, JavaThread::held_monitor_count_offset()));
         } else {
    diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
    index e10357c4a5a..4bd33d08f89 100644
    --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
    @@ -3659,8 +3659,394 @@ class StubGenerator: public StubCodeGenerator {
           return entry;
         }
       };
    +
     #endif // COMPILER2
     
    +#undef __
    +#define __ this->
    +  class Sha2Generator : public MacroAssembler {
    +    StubCodeGenerator* _cgen;
    +   public:
    +      Sha2Generator(MacroAssembler* masm, StubCodeGenerator* cgen) : MacroAssembler(masm->code()), _cgen(cgen) {}
    +      address generate_sha256_implCompress(bool multi_block) {
    +        return generate_sha2_implCompress(Assembler::e32, multi_block);
    +      }
    +      address generate_sha512_implCompress(bool multi_block) {
    +        return generate_sha2_implCompress(Assembler::e64, multi_block);
    +      }
    +   private:
    +
    +    void vleXX_v(Assembler::SEW vset_sew, VectorRegister vr, Register sr) {
    +      if (vset_sew == Assembler::e32) __ vle32_v(vr, sr);
    +      else                            __ vle64_v(vr, sr);
    +    }
    +
    +    void vseXX_v(Assembler::SEW vset_sew, VectorRegister vr, Register sr) {
    +      if (vset_sew == Assembler::e32) __ vse32_v(vr, sr);
    +      else                            __ vse64_v(vr, sr);
    +    }
    +
    +    // Overview of the logic in each "quad round".
    +    //
    +    // The code below repeats 16/20 times the logic implementing four rounds
    +    // of the SHA-256/512 core loop as documented by NIST. 16/20 "quad rounds"
    +    // to implementing the 64/80 single rounds.
    +    //
    +    //    // Load four word (u32/64) constants (K[t+3], K[t+2], K[t+1], K[t+0])
    +    //    // Output:
    +    //    //   vTmp1 = {K[t+3], K[t+2], K[t+1], K[t+0]}
    +    //    vl1reXX.v vTmp1, ofs
    +    //
    +    //    // Increment word constant address by stride (16/32 bytes, 4*4B/8B, 128b/256b)
    +    //    addi ofs, ofs, 16/32
    +    //
    +    //    // Add constants to message schedule words:
    +    //    //  Input
    +    //    //    vTmp1 = {K[t+3], K[t+2], K[t+1], K[t+0]}
    +    //    //    vW0 = {W[t+3], W[t+2], W[t+1], W[t+0]}; // Vt0 = W[3:0];
    +    //    //  Output
    +    //    //    vTmp0 = {W[t+3]+K[t+3], W[t+2]+K[t+2], W[t+1]+K[t+1], W[t+0]+K[t+0]}
    +    //    vadd.vv vTmp0, vTmp1, vW0
    +    //
    +    //    //  2 rounds of working variables updates.
    +    //    //     vState1[t+4] <- vState1[t], vState0[t], vTmp0[t]
    +    //    //  Input:
    +    //    //    vState1 = {c[t],d[t],g[t],h[t]}   " = vState1[t] "
    +    //    //    vState0 = {a[t],b[t],e[t],f[t]}
    +    //    //    vTmp0 = {W[t+3]+K[t+3], W[t+2]+K[t+2], W[t+1]+K[t+1], W[t+0]+K[t+0]}
    +    //    //  Output:
    +    //    //    vState1 = {f[t+2],e[t+2],b[t+2],a[t+2]}  " = vState0[t+2] "
    +    //    //        = {h[t+4],g[t+4],d[t+4],c[t+4]}  " = vState1[t+4] "
    +    //    vsha2cl.vv vState1, vState0, vTmp0
    +    //
    +    //    //  2 rounds of working variables updates.
    +    //    //     vState0[t+4] <- vState0[t], vState0[t+2], vTmp0[t]
    +    //    //  Input
    +    //    //   vState0 = {a[t],b[t],e[t],f[t]}       " = vState0[t] "
    +    //    //       = {h[t+2],g[t+2],d[t+2],c[t+2]}   " = vState1[t+2] "
    +    //    //   vState1 = {f[t+2],e[t+2],b[t+2],a[t+2]}   " = vState0[t+2] "
    +    //    //   vTmp0 = {W[t+3]+K[t+3], W[t+2]+K[t+2], W[t+1]+K[t+1], W[t+0]+K[t+0]}
    +    //    //  Output:
    +    //    //   vState0 = {f[t+4],e[t+4],b[t+4],a[t+4]}   " = vState0[t+4] "
    +    //    vsha2ch.vv vState0, vState1, vTmp0
    +    //
    +    //    // Combine 2QW into 1QW
    +    //    //
    +    //    // To generate the next 4 words, "new_vW0"/"vTmp0" from vW0-vW3, vsha2ms needs
    +    //    //     vW0[0..3], vW1[0], vW2[1..3], vW3[0, 2..3]
    +    //    // and it can only take 3 vectors as inputs. Hence we need to combine
    +    //    // vW1[0] and vW2[1..3] in a single vector.
    +    //    //
    +    //    // vmerge Vt4, Vt1, Vt2, V0
    +    //    // Input
    +    //    //  V0 = mask // first word from vW2, 1..3 words from vW1
    +    //    //  vW2 = {Wt-8, Wt-7, Wt-6, Wt-5}
    +    //    //  vW1 = {Wt-12, Wt-11, Wt-10, Wt-9}
    +    //    // Output
    +    //    //  Vt4 = {Wt-12, Wt-7, Wt-6, Wt-5}
    +    //    vmerge.vvm vTmp0, vW2, vW1, v0
    +    //
    +    //    // Generate next Four Message Schedule Words (hence allowing for 4 more rounds)
    +    //    // Input
    +    //    //  vW0 = {W[t+ 3], W[t+ 2], W[t+ 1], W[t+ 0]}     W[ 3: 0]
    +    //    //  vW3 = {W[t+15], W[t+14], W[t+13], W[t+12]}     W[15:12]
    +    //    //  vTmp0 = {W[t+11], W[t+10], W[t+ 9], W[t+ 4]}     W[11: 9,4]
    +    //    // Output (next four message schedule words)
    +    //    //  vW0 = {W[t+19],  W[t+18],  W[t+17],  W[t+16]}  W[19:16]
    +    //    vsha2ms.vv vW0, vTmp0, vW3
    +    //
    +    // BEFORE
    +    //  vW0 - vW3 hold the message schedule words (initially the block words)
    +    //    vW0 = W[ 3: 0]   "oldest"
    +    //    vW1 = W[ 7: 4]
    +    //    vW2 = W[11: 8]
    +    //    vW3 = W[15:12]   "newest"
    +    //
    +    //  vt6 - vt7 hold the working state variables
    +    //    vState0 = {a[t],b[t],e[t],f[t]}   // initially {H5,H4,H1,H0}
    +    //    vState1 = {c[t],d[t],g[t],h[t]}   // initially {H7,H6,H3,H2}
    +    //
    +    // AFTER
    +    //  vW0 - vW3 hold the message schedule words (initially the block words)
    +    //    vW1 = W[ 7: 4]   "oldest"
    +    //    vW2 = W[11: 8]
    +    //    vW3 = W[15:12]
    +    //    vW0 = W[19:16]   "newest"
    +    //
    +    //  vState0 and vState1 hold the working state variables
    +    //    vState0 = {a[t+4],b[t+4],e[t+4],f[t+4]}
    +    //    vState1 = {c[t+4],d[t+4],g[t+4],h[t+4]}
    +    //
    +    //  The group of vectors vW0,vW1,vW2,vW3 is "rotated" by one in each quad-round,
    +    //  hence the uses of those vectors rotate in each round, and we get back to the
    +    //  initial configuration every 4 quad-rounds. We could avoid those changes at
    +    //  the cost of moving those vectors at the end of each quad-rounds.
    +    void sha2_quad_round(Assembler::SEW vset_sew, VectorRegister rot1, VectorRegister rot2, VectorRegister rot3, VectorRegister rot4,
    +                         Register scalarconst, VectorRegister vtemp, VectorRegister vtemp2, VectorRegister v_abef, VectorRegister v_cdgh,
    +                         bool gen_words = true, bool step_const = true) {
    +      __ vleXX_v(vset_sew, vtemp, scalarconst);
    +      if (step_const) {
    +        __ addi(scalarconst, scalarconst, vset_sew == Assembler::e32 ? 16 : 32);
    +      }
    +      __ vadd_vv(vtemp2, vtemp, rot1);
    +      __ vsha2cl_vv(v_cdgh, v_abef, vtemp2);
    +      __ vsha2ch_vv(v_abef, v_cdgh, vtemp2);
    +      if (gen_words) {
    +        __ vmerge_vvm(vtemp2, rot3, rot2);
    +        __ vsha2ms_vv(rot1, vtemp2, rot4);
    +      }
    +    }
    +
    +    const char* stub_name(Assembler::SEW vset_sew, bool multi_block) {
    +      if (vset_sew == Assembler::e32 && !multi_block) return "sha256_implCompress";
    +      if (vset_sew == Assembler::e32 &&  multi_block) return "sha256_implCompressMB";
    +      if (vset_sew == Assembler::e64 && !multi_block) return "sha512_implCompress";
    +      if (vset_sew == Assembler::e64 &&  multi_block) return "sha512_implCompressMB";
    +      ShouldNotReachHere();
    +      return "bad name lookup";
    +    }
    +
    +    // Arguments:
    +    //
    +    // Inputs:
    +    //   c_rarg0   - byte[]  source+offset
    +    //   c_rarg1   - int[]   SHA.state
    +    //   c_rarg2   - int     offset
    +    //   c_rarg3   - int     limit
    +    //
    +    address generate_sha2_implCompress(Assembler::SEW vset_sew, bool multi_block) {
    +      alignas(64) static const uint32_t round_consts_256[64] = {
    +        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
    +        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    +        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
    +        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    +        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
    +        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    +        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
    +        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    +        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
    +        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    +        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
    +        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    +        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
    +        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    +        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
    +        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
    +      };
    +      alignas(64) static const uint64_t round_consts_512[80] = {
    +        0x428a2f98d728ae22l, 0x7137449123ef65cdl, 0xb5c0fbcfec4d3b2fl,
    +        0xe9b5dba58189dbbcl, 0x3956c25bf348b538l, 0x59f111f1b605d019l,
    +        0x923f82a4af194f9bl, 0xab1c5ed5da6d8118l, 0xd807aa98a3030242l,
    +        0x12835b0145706fbel, 0x243185be4ee4b28cl, 0x550c7dc3d5ffb4e2l,
    +        0x72be5d74f27b896fl, 0x80deb1fe3b1696b1l, 0x9bdc06a725c71235l,
    +        0xc19bf174cf692694l, 0xe49b69c19ef14ad2l, 0xefbe4786384f25e3l,
    +        0x0fc19dc68b8cd5b5l, 0x240ca1cc77ac9c65l, 0x2de92c6f592b0275l,
    +        0x4a7484aa6ea6e483l, 0x5cb0a9dcbd41fbd4l, 0x76f988da831153b5l,
    +        0x983e5152ee66dfabl, 0xa831c66d2db43210l, 0xb00327c898fb213fl,
    +        0xbf597fc7beef0ee4l, 0xc6e00bf33da88fc2l, 0xd5a79147930aa725l,
    +        0x06ca6351e003826fl, 0x142929670a0e6e70l, 0x27b70a8546d22ffcl,
    +        0x2e1b21385c26c926l, 0x4d2c6dfc5ac42aedl, 0x53380d139d95b3dfl,
    +        0x650a73548baf63del, 0x766a0abb3c77b2a8l, 0x81c2c92e47edaee6l,
    +        0x92722c851482353bl, 0xa2bfe8a14cf10364l, 0xa81a664bbc423001l,
    +        0xc24b8b70d0f89791l, 0xc76c51a30654be30l, 0xd192e819d6ef5218l,
    +        0xd69906245565a910l, 0xf40e35855771202al, 0x106aa07032bbd1b8l,
    +        0x19a4c116b8d2d0c8l, 0x1e376c085141ab53l, 0x2748774cdf8eeb99l,
    +        0x34b0bcb5e19b48a8l, 0x391c0cb3c5c95a63l, 0x4ed8aa4ae3418acbl,
    +        0x5b9cca4f7763e373l, 0x682e6ff3d6b2b8a3l, 0x748f82ee5defb2fcl,
    +        0x78a5636f43172f60l, 0x84c87814a1f0ab72l, 0x8cc702081a6439ecl,
    +        0x90befffa23631e28l, 0xa4506cebde82bde9l, 0xbef9a3f7b2c67915l,
    +        0xc67178f2e372532bl, 0xca273eceea26619cl, 0xd186b8c721c0c207l,
    +        0xeada7dd6cde0eb1el, 0xf57d4f7fee6ed178l, 0x06f067aa72176fbal,
    +        0x0a637dc5a2c898a6l, 0x113f9804bef90dael, 0x1b710b35131c471bl,
    +        0x28db77f523047d84l, 0x32caab7b40c72493l, 0x3c9ebe0a15c9bebcl,
    +        0x431d67c49c100d4cl, 0x4cc5d4becb3e42b6l, 0x597f299cfc657e2al,
    +        0x5fcb6fab3ad6faecl, 0x6c44198c4a475817l
    +      };
    +      const int const_add = vset_sew == Assembler::e32 ? 16 : 32;
    +
    +      __ align(CodeEntryAlignment);
    +      StubCodeMark mark(_cgen, "StubRoutines", stub_name(vset_sew, multi_block));
    +      address start = __ pc();
    +
    +      Register buf   = c_rarg0;
    +      Register state = c_rarg1;
    +      Register ofs   = c_rarg2;
    +      Register limit = c_rarg3;
    +      Register consts =  t2; // caller saved
    +      Register state_c = x28; // caller saved
    +      VectorRegister vindex = v2;
    +      VectorRegister vW0 = v4;
    +      VectorRegister vW1 = v6;
    +      VectorRegister vW2 = v8;
    +      VectorRegister vW3 = v10;
    +      VectorRegister vState0 = v12;
    +      VectorRegister vState1 = v14;
    +      VectorRegister vHash0  = v16;
    +      VectorRegister vHash1  = v18;
    +      VectorRegister vTmp0   = v20;
    +      VectorRegister vTmp1   = v22;
    +
    +      Label multi_block_loop;
    +
    +      __ enter();
    +
    +      address constant_table = vset_sew == Assembler::e32 ? (address)round_consts_256 : (address)round_consts_512;
    +      la(consts, ExternalAddress(constant_table));
    +
    +      // Register use in this function:
    +      //
    +      // VECTORS
    +      //  vW0 - vW3 (512/1024-bits / 4*128/256 bits / 4*4*32/65 bits), hold the message
    +      //             schedule words (Wt). They start with the message block
    +      //             content (W0 to W15), then further words in the message
    +      //             schedule generated via vsha2ms from previous Wt.
    +      //   Initially:
    +      //     vW0 = W[  3:0] = { W3,  W2,  W1,  W0}
    +      //     vW1 = W[  7:4] = { W7,  W6,  W5,  W4}
    +      //     vW2 = W[ 11:8] = {W11, W10,  W9,  W8}
    +      //     vW3 = W[15:12] = {W15, W14, W13, W12}
    +      //
    +      //  vState0 - vState1 hold the working state variables (a, b, ..., h)
    +      //    vState0 = {f[t],e[t],b[t],a[t]}
    +      //    vState1 = {h[t],g[t],d[t],c[t]}
    +      //   Initially:
    +      //    vState0 = {H5i-1, H4i-1, H1i-1 , H0i-1}
    +      //    vState1 = {H7i-i, H6i-1, H3i-1 , H2i-1}
    +      //
    +      //  v0 = masks for vrgather/vmerge. Single value during the 16 rounds.
    +      //
    +      //  vTmp0 = temporary, Wt+Kt
    +      //  vTmp1 = temporary, Kt
    +      //
    +      //  vHash0/vHash1 = hold the initial values of the hash, byte-swapped.
    +      //
    +      // During most of the function the vector state is configured so that each
    +      // vector is interpreted as containing four 32/64 bits (e32/e64) elements (128/256 bits).
    +
    +      // vsha2ch/vsha2cl uses EGW of 4*SEW.
    +      // SHA256 SEW = e32, EGW = 128-bits
    +      // SHA512 SEW = e64, EGW = 256-bits
    +      //
    +      // VLEN is required to be at least 128.
    +      // For the case of VLEN=128 and SHA512 we need LMUL=2 to work with 4*e64 (EGW = 256)
    +      //
    +      // m1: LMUL=1/2
    +      // ta: tail agnostic (don't care about those lanes)
    +      // ma: mask agnostic (don't care about those lanes)
    +      // x0 is not written, we known the number of vector elements.
    +
    +      if (vset_sew == Assembler::e64 && MaxVectorSize == 16) { // SHA512 and VLEN = 128
    +        __ vsetivli(x0, 4, vset_sew, Assembler::m2, Assembler::ma, Assembler::ta);
    +      } else {
    +        __ vsetivli(x0, 4, vset_sew, Assembler::m1, Assembler::ma, Assembler::ta);
    +      }
    +
    +      int64_t indexes = vset_sew == Assembler::e32 ? 0x00041014ul : 0x00082028ul;
    +      __ li(t0, indexes);
    +      __ vmv_v_x(vindex, t0);
    +
    +      // Step-over a,b, so we are pointing to c.
    +      // const_add is equal to 4x state variable, div by 2 is thus 2, a,b
    +      __ addi(state_c, state, const_add/2);
    +
    +      // Use index-load to get {f,e,b,a},{h,g,d,c}
    +      __ vluxei8_v(vState0, state, vindex);
    +      __ vluxei8_v(vState1, state_c, vindex);
    +
    +      __ bind(multi_block_loop);
    +
    +      // Capture the initial H values in vHash0 and vHash1 to allow for computing
    +      // the resulting H', since H' = H+{a',b',c',...,h'}.
    +      __ vmv_v_v(vHash0, vState0);
    +      __ vmv_v_v(vHash1, vState1);
    +
    +      // Load the 512/1024-bits of the message block in vW0-vW3 and perform
    +      // an endian swap on each 4/8 bytes element.
    +      //
    +      // If Zvkb is not implemented one can use vrgather
    +      // with an index sequence to byte-swap.
    +      //  sequence = [3 2 1 0   7 6 5 4  11 10 9 8   15 14 13 12]
    +      //    gives us "N ^ 3" as a nice formula to generate
    +      //  this sequence. 'vid' gives us the N.
    +      __ vleXX_v(vset_sew, vW0, buf);
    +      __ vrev8_v(vW0, vW0);
    +      __ addi(buf, buf, const_add);
    +      __ vleXX_v(vset_sew, vW1, buf);
    +      __ vrev8_v(vW1, vW1);
    +      __ addi(buf, buf, const_add);
    +      __ vleXX_v(vset_sew, vW2, buf);
    +      __ vrev8_v(vW2, vW2);
    +      __ addi(buf, buf, const_add);
    +      __ vleXX_v(vset_sew, vW3, buf);
    +      __ vrev8_v(vW3, vW3);
    +      __ addi(buf, buf, const_add);
    +
    +      // Set v0 up for the vmerge that replaces the first word (idx==0)
    +      __ vid_v(v0);
    +      __ vmseq_vi(v0, v0, 0x0);  // v0.mask[i] = (i == 0 ? 1 : 0)
    +
    +      VectorRegister rotation_regs[] = {vW0, vW1, vW2, vW3};
    +      int rot_pos = 0;
    +      // Quad-round #0 (+0, vW0->vW1->vW2->vW3) ... #11 (+3, vW3->vW0->vW1->vW2)
    +      const int qr_end = vset_sew == Assembler::e32 ? 12 : 16;
    +      for (int i = 0; i < qr_end; i++) {
    +        sha2_quad_round(vset_sew,
    +                   rotation_regs[(rot_pos + 0) & 0x3],
    +                   rotation_regs[(rot_pos + 1) & 0x3],
    +                   rotation_regs[(rot_pos + 2) & 0x3],
    +                   rotation_regs[(rot_pos + 3) & 0x3],
    +                   consts,
    +                   vTmp1, vTmp0, vState0, vState1);
    +        ++rot_pos;
    +      }
    +      // Quad-round #12 (+0, vW0->vW1->vW2->vW3) ... #15 (+3, vW3->vW0->vW1->vW2)
    +      // Note that we stop generating new message schedule words (Wt, vW0-13)
    +      // as we already generated all the words we end up consuming (i.e., W[63:60]).
    +      const int qr_c_end = qr_end + 4;
    +      for (int i = qr_end; i < qr_c_end; i++) {
    +        sha2_quad_round(vset_sew,
    +                   rotation_regs[(rot_pos + 0) & 0x3],
    +                   rotation_regs[(rot_pos + 1) & 0x3],
    +                   rotation_regs[(rot_pos + 2) & 0x3],
    +                   rotation_regs[(rot_pos + 3) & 0x3],
    +                   consts,
    +                   vTmp1, vTmp0, vState0, vState1, false, i < (qr_c_end-1));
    +        ++rot_pos;
    +      }
    +
    +      //--------------------------------------------------------------------------------
    +      // Compute the updated hash value H'
    +      //   H' = H + {h',g',...,b',a'}
    +      //      = {h,g,...,b,a} + {h',g',...,b',a'}
    +      //      = {h+h',g+g',...,b+b',a+a'}
    +
    +      // H' = H+{a',b',c',...,h'}
    +      __ vadd_vv(vState0, vHash0, vState0);
    +      __ vadd_vv(vState1, vHash1, vState1);
    +
    +      if (multi_block) {
    +        int total_adds = vset_sew == Assembler::e32 ? 240 : 608;
    +        __ addi(consts, consts, -total_adds);
    +        __ add(ofs, ofs, vset_sew == Assembler::e32 ? 64 : 128);
    +        __ ble(ofs, limit, multi_block_loop);
    +        __ mv(c_rarg0, ofs); // return ofs
    +      }
    +
    +      // Store H[0..8] = {a,b,c,d,e,f,g,h} from
    +      //  vState0 = {f,e,b,a}
    +      //  vState1 = {h,g,d,c}
    +      __ vsuxei8_v(vState0, state,   vindex);
    +      __ vsuxei8_v(vState1, state_c, vindex);
    +
    +      __ leave();
    +      __ ret();
    +
    +      return start;
    +    }
    +  };
    +#undef __
    +#define __ masm->
    +
       // Continuation point for throwing of implicit exceptions that are
       // not handled in the current activation. Fabricates an exception
       // oop and initiates normal exception dispatching in this
    @@ -4155,14 +4541,18 @@ class StubGenerator: public StubCodeGenerator {
     
         // to minimize the number of memory operations:
         // read the 4 state 4-byte values in pairs, with a single ld,
    -    // and split them into 2 registers
    -    __ mv(t0, mask32);
    +    // and split them into 2 registers.
    +    //
    +    // And, as the core algorithm of md5 works on 32-bits words, so
    +    // in the following code, it does not care about the content of
    +    // higher 32-bits in state[x]. Based on this observation,
    +    // we can apply further optimization, which is to just ignore the
    +    // higher 32-bits in state0/state2, rather than set the higher
    +    // 32-bits of state0/state2 to zero explicitly with extra instructions.
         __ ld(state0, Address(state));
         __ srli(state1, state0, 32);
    -    __ andr(state0, state0, t0);
         __ ld(state2, Address(state, 8));
         __ srli(state3, state2, 32);
    -    __ andr(state2, state2, t0);
     
         Label md5_loop;
         __ BIND(md5_loop);
    @@ -4858,6 +5248,18 @@ static const int64_t right_3_bits = right_n_bits(3);
         }
     #endif // COMPILER2
     
    +    if (UseSHA256Intrinsics) {
    +      Sha2Generator sha2(_masm, this);
    +      StubRoutines::_sha256_implCompress   = sha2.generate_sha256_implCompress(false);
    +      StubRoutines::_sha256_implCompressMB = sha2.generate_sha256_implCompress(true);
    +    }
    +
    +    if (UseSHA512Intrinsics) {
    +      Sha2Generator sha2(_masm, this);
    +      StubRoutines::_sha512_implCompress   = sha2.generate_sha512_implCompress(false);
    +      StubRoutines::_sha512_implCompressMB = sha2.generate_sha512_implCompress(true);
    +    }
    +
         generate_compare_long_strings();
     
         generate_string_indexof_stubs();
    diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
    index fc83e629858..9a72b8d75a1 100644
    --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
    @@ -146,26 +146,11 @@ void VM_Version::initialize() {
         FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
       }
     
    -  if (UseSHA) {
    -    warning("SHA instructions are not available on this CPU");
    -    FLAG_SET_DEFAULT(UseSHA, false);
    -  }
    -
       if (UseSHA1Intrinsics) {
         warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
         FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
       }
     
    -  if (UseSHA256Intrinsics) {
    -    warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
    -    FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
    -  }
    -
    -  if (UseSHA512Intrinsics) {
    -    warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
    -    FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
    -  }
    -
       if (UseSHA3Intrinsics) {
         warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
         FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
    @@ -272,6 +257,10 @@ void VM_Version::initialize() {
       // NOTE: Make sure codes dependent on UseRVV are put after c2_initialize(),
       //       as there are extra checks inside it which could disable UseRVV
       //       in some situations.
    +  if (UseZvkn && !UseRVV) {
    +    FLAG_SET_DEFAULT(UseZvkn, false);
    +    warning("Cannot enable Zvkn on cpu without RVV support.");
    +  }
     
       if (UseRVV) {
         if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) {
    @@ -283,6 +272,31 @@ void VM_Version::initialize() {
         }
         FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false);
       }
    +
    +  if (!UseZvkn && UseSHA) {
    +    warning("SHA instructions are not available on this CPU");
    +    FLAG_SET_DEFAULT(UseSHA, false);
    +  } else if (UseZvkn && FLAG_IS_DEFAULT(UseSHA)) {
    +    FLAG_SET_DEFAULT(UseSHA, true);
    +  }
    +
    +  if (!UseSHA) {
    +    if (UseSHA256Intrinsics) {
    +      warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU, UseZvkn needed.");
    +      FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
    +    }
    +    if (UseSHA512Intrinsics) {
    +      warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU, UseZvkn needed.");
    +      FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
    +    }
    +  } else {
    +    if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
    +       FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
    +    }
    +    if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
    +      FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
    +    }
    +  }
     }
     
     #ifdef COMPILER2
    @@ -315,6 +329,10 @@ void VM_Version::c2_initialize() {
         }
       }
     
    +  if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) {
    +    FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true);
    +  }
    +
       if (!UseZicbop) {
         if (!FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
           warning("Zicbop is not available on this CPU");
    diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
    index 3c769ebfe2a..1ea853284ff 100644
    --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp
    +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
    @@ -110,6 +110,9 @@ class VM_Version : public Abstract_VM_Version {
       // Zic64b Cache blocks must be 64 bytes in size, naturally aligned in the address space.
       // Zihintpause Pause instruction HINT
       //
    +  // Zc  Code Size Reduction - Additional compressed instructions.
    +  // Zcb Simple code-size saving instructions
    +  //
       // Other features and settings
       // mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2..
       // marchid   Id for microarch. Mvendorid plus marchid uniquely identify the microarch.
    @@ -117,6 +120,8 @@ class VM_Version : public Abstract_VM_Version {
       // unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast)
       // satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64
     
    + public:
    +
       #define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord
     
       // declaration name  , extension name,    bit pos ,in str, mapped flag)
    @@ -137,11 +142,13 @@ class VM_Version : public Abstract_VM_Version {
       decl(ext_Zbb         , "Zbb"         , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb))         \
       decl(ext_Zbc         , "Zbc"         , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT)              \
       decl(ext_Zbs         , "Zbs"         , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs))         \
    +  decl(ext_Zcb         , "Zcb"         , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT)              \
       decl(ext_Zicsr       , "Zicsr"       , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT)              \
       decl(ext_Zifencei    , "Zifencei"    , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT)              \
       decl(ext_Zic64b      , "Zic64b"      , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b))      \
       decl(ext_Ztso        , "Ztso"        , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso))        \
       decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
    +  decl(ext_Zacas       , "Zacas"       , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas))       \
       decl(mvendorid       , "VendorId"    , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT)              \
       decl(marchid         , "ArchId"      , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT)              \
       decl(mimpid          , "ImpId"       , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT)              \
    @@ -208,6 +215,9 @@ class VM_Version : public Abstract_VM_Version {
       constexpr static bool supports_stack_watermark_barrier() { return true; }
     
       static bool supports_on_spin_wait() { return UseZihintpause; }
    +
    +  // RISCV64 supports fast class initialization checks
    +  static bool supports_fast_class_init_checks() { return true; }
     };
     
     #endif // CPU_RISCV_VM_VERSION_RISCV_HPP
    diff --git a/src/hotspot/cpu/s390/compiledIC_s390.cpp b/src/hotspot/cpu/s390/compiledIC_s390.cpp
    index 09822425e12..7ea90c1de7c 100644
    --- a/src/hotspot/cpu/s390/compiledIC_s390.cpp
    +++ b/src/hotspot/cpu/s390/compiledIC_s390.cpp
    @@ -95,9 +95,9 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
       address stub = find_stub();
       guarantee(stub != nullptr, "stub not found");
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
    +    log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                       p2i(instruction_address()),
                       callee->name_and_sig_as_C_string());
       }
    diff --git a/src/hotspot/cpu/s390/frame_s390.hpp b/src/hotspot/cpu/s390/frame_s390.hpp
    index 3f81cd254d0..06433d9136f 100644
    --- a/src/hotspot/cpu/s390/frame_s390.hpp
    +++ b/src/hotspot/cpu/s390/frame_s390.hpp
    @@ -465,7 +465,6 @@
     
       // Initialize frame members (_pc and _sp must be given)
       inline void setup();
    -  const ImmutableOopMap* get_oop_map() const;
     
      // Constructors
     
    diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp
    index 91a6917c319..178f7f90849 100644
    --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp
    +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp
    @@ -292,20 +292,6 @@ inline intptr_t* frame::real_fp() const {
       return fp();
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  if (_cb == nullptr) return nullptr;
    -  if (_cb->oop_maps() != nullptr) {
    -    NativePostCallNop* nop = nativePostCallNop_at(_pc);
    -    if (nop != nullptr && nop->displacement() != 0) {
    -      int slot = ((nop->displacement() >> 24) & 0xff);
    -      return _cb->oop_map_for_slot(slot, _pc);
    -    }
    -    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    -    return oop_map;
    -  }
    -  return nullptr;
    -}
    -
     inline int frame::compiled_frame_stack_argsize() const {
       Unimplemented();
       return 0;
    diff --git a/src/hotspot/cpu/s390/globalDefinitions_s390.hpp b/src/hotspot/cpu/s390/globalDefinitions_s390.hpp
    index 39baf5bf047..236d4c5bf69 100644
    --- a/src/hotspot/cpu/s390/globalDefinitions_s390.hpp
    +++ b/src/hotspot/cpu/s390/globalDefinitions_s390.hpp
    @@ -48,6 +48,9 @@ const bool CCallingConventionRequiresIntsAsLongs = true;
     // The expected size in bytes of a cache line, used to pad data structures.
     #define DEFAULT_CACHE_LINE_SIZE 256
     
    +// The default padding size for data structures to avoid false sharing.
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
    +
     #define SUPPORT_RESERVED_STACK_AREA
     
     #endif // CPU_S390_GLOBALDEFINITIONS_S390_HPP
    diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp
    index e68dca34c3b..450ea35a6cb 100644
    --- a/src/hotspot/cpu/s390/matcher_s390.hpp
    +++ b/src/hotspot/cpu/s390/matcher_s390.hpp
    @@ -184,4 +184,9 @@
         }
       }
     
    +  // Is SIMD sort supported for this CPU?
    +  static bool supports_simd_sort(BasicType bt) {
    +    return false;
    +  }
    +
     #endif // CPU_S390_MATCHER_S390_HPP
    diff --git a/src/hotspot/cpu/s390/nativeInst_s390.hpp b/src/hotspot/cpu/s390/nativeInst_s390.hpp
    index 65bfe499370..abad50da8b4 100644
    --- a/src/hotspot/cpu/s390/nativeInst_s390.hpp
    +++ b/src/hotspot/cpu/s390/nativeInst_s390.hpp
    @@ -657,8 +657,8 @@ class NativeGeneralJump: public NativeInstruction {
     class NativePostCallNop: public NativeInstruction {
     public:
       bool check() const { Unimplemented(); return false; }
    -  int displacement() const { return 0; }
    -  void patch(jint diff) { Unimplemented(); }
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const { return false; }
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset) { Unimplemented(); return false; }
       void make_deopt() { Unimplemented(); }
     };
     
    diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
    index 4798f35f19d..ed1795cfa33 100644
    --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
    +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
    @@ -755,7 +755,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
             ShouldNotReachHere();
         }
       }
    -  return align_up(stk, 2);
    +  return stk;
     }
     
     int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
    diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp
    index d72e2712a40..93d5b11c473 100644
    --- a/src/hotspot/cpu/s390/vm_version_s390.hpp
    +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp
    @@ -410,7 +410,7 @@ class VM_Version: public Abstract_VM_Version {
       // Override Abstract_VM_Version implementation
       static void print_platform_virtualization_info(outputStream*);
     
    -  // s390 supports fast class initialization checks for static methods.
    +  // s390 supports fast class initialization checks
       static bool supports_fast_class_init_checks() { return true; }
     
       // CPU feature query functions
    diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp
    index cedddaed975..63d6ec9b00f 100644
    --- a/src/hotspot/cpu/x86/assembler_x86.cpp
    +++ b/src/hotspot/cpu/x86/assembler_x86.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -889,8 +889,8 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
         assert(which == imm_operand || which == disp32_operand,
                "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip));
     #else
    -    assert((which == call32_operand || which == imm_operand) && is_64bit ||
    -           which == narrow_oop_operand && !is_64bit,
    +    assert(((which == call32_operand || which == imm_operand) && is_64bit) ||
    +           (which == narrow_oop_operand && !is_64bit),
                "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip));
     #endif // _LP64
         return ip;
    @@ -920,6 +920,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
         case 0x11: // movups
         case 0x12: // movlps
         case 0x28: // movaps
    +    case 0x29: // movaps
         case 0x2E: // ucomiss
         case 0x2F: // comiss
         case 0x54: // andps
    @@ -969,7 +970,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
           assert(which == call32_operand, "jcc has no disp32 or imm");
           return ip;
         default:
    -      ShouldNotReachHere();
    +      fatal("not handled: 0x0F%2X", 0xFF & *(ip-1));
         }
         break;
     
    @@ -2845,6 +2846,13 @@ void Assembler::kxorbl(KRegister dst, KRegister src1, KRegister src2) {
       emit_int16(0x47, (0xC0 | encode));
     }
     
    +void Assembler::kxnorwl(KRegister dst, KRegister src1, KRegister src2) {
    +  assert(VM_Version::supports_evex(), "");
    +  InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
    +  int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
    +  emit_int16(0x46, (0xC0 | encode));
    +}
    +
     void Assembler::kxorwl(KRegister dst, KRegister src1, KRegister src2) {
       assert(VM_Version::supports_evex(), "");
       InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
    @@ -7227,7 +7235,7 @@ void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src, int vector
     
     // Integer vector arithmetic
     void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
    -  assert(VM_Version::supports_avx() && (vector_len == 0) ||
    +  assert((VM_Version::supports_avx() && (vector_len == 0)) ||
              VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
       InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);
       int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
    @@ -7235,7 +7243,7 @@ void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int v
     }
     
     void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
    -  assert(VM_Version::supports_avx() && (vector_len == 0) ||
    +  assert((VM_Version::supports_avx() && (vector_len == 0)) ||
              VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
       InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);
       int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
    @@ -10770,7 +10778,7 @@ void Assembler::vpgatherdd(XMMRegister dst, Address src, XMMRegister mask, int v
       assert(src.isxmmindex(),"expected to be xmm index");
       assert(dst != src.xmmindex(), "instruction will #UD if dst and index are the same");
       InstructionMark im(this);
    -  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);
    +  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
       vex_prefix(src, mask->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
       emit_int8((unsigned char)0x90);
       emit_operand(dst, src, 0);
    @@ -10783,7 +10791,7 @@ void Assembler::vpgatherdq(XMMRegister dst, Address src, XMMRegister mask, int v
       assert(src.isxmmindex(),"expected to be xmm index");
       assert(dst != src.xmmindex(), "instruction will #UD if dst and index are the same");
       InstructionMark im(this);
    -  InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);
    +  InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
       vex_prefix(src, mask->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
       emit_int8((unsigned char)0x90);
       emit_operand(dst, src, 0);
    @@ -10796,7 +10804,7 @@ void Assembler::vgatherdpd(XMMRegister dst, Address src, XMMRegister mask, int v
       assert(src.isxmmindex(),"expected to be xmm index");
       assert(dst != src.xmmindex(), "instruction will #UD if dst and index are the same");
       InstructionMark im(this);
    -  InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);
    +  InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
       vex_prefix(src, mask->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
       emit_int8((unsigned char)0x92);
       emit_operand(dst, src, 0);
    @@ -10809,7 +10817,7 @@ void Assembler::vgatherdps(XMMRegister dst, Address src, XMMRegister mask, int v
       assert(src.isxmmindex(),"expected to be xmm index");
       assert(dst != src.xmmindex(), "instruction will #UD if dst and index are the same");
       InstructionMark im(this);
    -  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ true);
    +  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
       vex_prefix(src, mask->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
       emit_int8((unsigned char)0x92);
       emit_operand(dst, src, 0);
    diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp
    index 1d3e43141f2..df148cb0c7e 100644
    --- a/src/hotspot/cpu/x86/assembler_x86.hpp
    +++ b/src/hotspot/cpu/x86/assembler_x86.hpp
    @@ -1524,6 +1524,8 @@ class Assembler : public AbstractAssembler  {
       void kordl(KRegister dst, KRegister src1, KRegister src2);
       void korql(KRegister dst, KRegister src1, KRegister src2);
     
    +  void kxnorwl(KRegister dst, KRegister src1, KRegister src2);
    +
       void kxorbl(KRegister dst, KRegister src1, KRegister src2);
       void kxorwl(KRegister dst, KRegister src1, KRegister src2);
       void kxordl(KRegister dst, KRegister src1, KRegister src2);
    diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
    index 88cee688137..ac07ea759fb 100644
    --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
    +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -5252,8 +5252,8 @@ void C2_MacroAssembler::vector_mask_operation(int opc, Register dst, KRegister m
     
     void C2_MacroAssembler::vector_mask_operation(int opc, Register dst, XMMRegister mask, XMMRegister xtmp,
                                                   Register tmp, int masklen, BasicType bt, int vec_enc) {
    -  assert(vec_enc == AVX_128bit && VM_Version::supports_avx() ||
    -         vec_enc == AVX_256bit && (VM_Version::supports_avx2() || type2aelembytes(bt) >= 4), "");
    +  assert((vec_enc == AVX_128bit && VM_Version::supports_avx()) ||
    +         (vec_enc == AVX_256bit && (VM_Version::supports_avx2() || type2aelembytes(bt) >= 4)), "");
       assert(VM_Version::supports_popcnt(), "");
     
       bool need_clip = false;
    diff --git a/src/hotspot/cpu/x86/compiledIC_x86.cpp b/src/hotspot/cpu/x86/compiledIC_x86.cpp
    index 39e8aafcd93..8fc001039fb 100644
    --- a/src/hotspot/cpu/x86/compiledIC_x86.cpp
    +++ b/src/hotspot/cpu/x86/compiledIC_x86.cpp
    @@ -28,6 +28,7 @@
     #include "code/compiledIC.hpp"
     #include "code/icBuffer.hpp"
     #include "code/nmethod.hpp"
    +#include "logging/log.hpp"
     #include "memory/resourceArea.hpp"
     #include "runtime/mutexLocker.hpp"
     #include "runtime/safepoint.hpp"
    @@ -84,9 +85,9 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
       address stub = find_stub();
       guarantee(stub != nullptr, "stub not found");
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
    +    log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                       p2i(instruction_address()),
                       callee->name_and_sig_as_C_string());
       }
    diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp
    index 8c073116280..27beeeb7f44 100644
    --- a/src/hotspot/cpu/x86/frame_x86.hpp
    +++ b/src/hotspot/cpu/x86/frame_x86.hpp
    @@ -152,8 +152,6 @@
       static void verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp);
     #endif
     
    -  const ImmutableOopMap* get_oop_map() const;
    -
      public:
       // Constructors
     
    diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp
    index 893538bb7e9..d88c8eab683 100644
    --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp
    +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -184,7 +184,7 @@ inline bool frame::equal(frame other) const {
                   && unextended_sp() == other.unextended_sp()
                   && fp() == other.fp()
                   && pc() == other.pc();
    -  assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
    +  assert(!ret || (ret && cb() == other.cb() && _deopt_state == other._deopt_state), "inconsistent construction");
       return ret;
     }
     
    @@ -346,20 +346,6 @@ inline int frame::sender_sp_ret_address_offset() {
       return frame::sender_sp_offset - frame::return_addr_offset;
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  if (_cb == nullptr) return nullptr;
    -  if (_cb->oop_maps() != nullptr) {
    -    NativePostCallNop* nop = nativePostCallNop_at(_pc);
    -    if (nop != nullptr && nop->displacement() != 0) {
    -      int slot = ((nop->displacement() >> 24) & 0xff);
    -      return _cb->oop_map_for_slot(slot, _pc);
    -    }
    -    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    -    return oop_map;
    -  }
    -  return nullptr;
    -}
    -
     //------------------------------------------------------------------------------
     // frame::sender
     
    diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
    index 7eff43471b5..2e82453b380 100644
    --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
    +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
    @@ -38,29 +38,18 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
     
     #define CPU_MULTI_COPY_ATOMIC
     
    -// The expected size in bytes of a cache line, used to pad data structures.
    -#if COMPILER1_AND_COMPILER2
    -  #ifdef _LP64
    -    // tiered, 64-bit, large machine
    -    #define DEFAULT_CACHE_LINE_SIZE 128
    -    #define OM_CACHE_LINE_SIZE 64
    -  #else
    -    // tiered, 32-bit, medium machine
    -    #define DEFAULT_CACHE_LINE_SIZE 64
    -  #endif
    -#elif defined(COMPILER1)
    -  // pure C1, 32-bit, small machine
    -  // i486 was the last Intel chip with 16-byte cache line size
    -  #define DEFAULT_CACHE_LINE_SIZE 32
    -#elif defined(COMPILER2)
    -  #ifdef _LP64
    -    // pure C2, 64-bit, large machine
    -    #define DEFAULT_CACHE_LINE_SIZE 128
    -    #define OM_CACHE_LINE_SIZE 64
    -  #else
    -    // pure C2, 32-bit, medium machine
    -    #define DEFAULT_CACHE_LINE_SIZE 64
    -  #endif
    +// The expected size in bytes of a cache line.
    +#define DEFAULT_CACHE_LINE_SIZE 64
    +
    +// The default padding size for data structures to avoid false sharing.
    +#ifdef _LP64
    +// The common wisdom is that adjacent cache line prefetchers on some hardware
    +// may pull two cache lines on access, so we have to pessimistically assume twice
    +// the cache line size for padding. TODO: Check if this is still true for modern
    +// hardware. If not, DEFAULT_CACHE_LINE_SIZE might as well suffice.
    +#define DEFAULT_PADDING_SIZE (DEFAULT_CACHE_LINE_SIZE*2)
    +#else
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
     #endif
     
     #if defined(COMPILER2)
    diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
    index 96d840adf6d..38fa0eb0671 100644
    --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
    +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
    @@ -1882,92 +1882,6 @@ void MacroAssembler::cmpoop(Register src1, jobject src2, Register rscratch) {
     }
     #endif
     
    -void MacroAssembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
    -  if ((UseAVX > 0) && (dst != src)) {
    -    xorpd(dst, dst);
    -  }
    -  Assembler::cvtss2sd(dst, src);
    -}
    -
    -void MacroAssembler::cvtss2sd(XMMRegister dst, Address src) {
    -  if (UseAVX > 0) {
    -    xorpd(dst, dst);
    -  }
    -  Assembler::cvtss2sd(dst, src);
    -}
    -
    -void MacroAssembler::cvtsd2ss(XMMRegister dst, XMMRegister src) {
    -  if ((UseAVX > 0) && (dst != src)) {
    -    xorps(dst, dst);
    -  }
    -  Assembler::cvtsd2ss(dst, src);
    -}
    -
    -void MacroAssembler::cvtsd2ss(XMMRegister dst, Address src) {
    -  if (UseAVX > 0) {
    -    xorps(dst, dst);
    -  }
    -  Assembler::cvtsd2ss(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2sdl(XMMRegister dst, Register src) {
    -  if (UseAVX > 0) {
    -    xorpd(dst, dst);
    -  }
    -  Assembler::cvtsi2sdl(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2sdl(XMMRegister dst, Address src) {
    -  if (UseAVX > 0) {
    -    xorpd(dst, dst);
    -  }
    -  Assembler::cvtsi2sdl(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2ssl(XMMRegister dst, Register src) {
    -  if (UseAVX > 0) {
    -    xorps(dst, dst);
    -  }
    -  Assembler::cvtsi2ssl(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2ssl(XMMRegister dst, Address src) {
    -  if (UseAVX > 0) {
    -    xorps(dst, dst);
    -  }
    -  Assembler::cvtsi2ssl(dst, src);
    -}
    -
    -#ifdef _LP64
    -void MacroAssembler::cvtsi2sdq(XMMRegister dst, Register src) {
    -  if (UseAVX > 0) {
    -    xorpd(dst, dst);
    -  }
    -  Assembler::cvtsi2sdq(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2sdq(XMMRegister dst, Address src) {
    -  if (UseAVX > 0) {
    -    xorpd(dst, dst);
    -  }
    -  Assembler::cvtsi2sdq(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2ssq(XMMRegister dst, Register src) {
    -  if (UseAVX > 0) {
    -    xorps(dst, dst);
    -  }
    -  Assembler::cvtsi2ssq(dst, src);
    -}
    -
    -void MacroAssembler::cvtsi2ssq(XMMRegister dst, Address src) {
    -  if (UseAVX > 0) {
    -    xorps(dst, dst);
    -  }
    -  Assembler::cvtsi2ssq(dst, src);
    -}
    -#endif  // _LP64
    -
     void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch) {
       assert(rscratch != noreg || always_reachable(adr), "missing");
     
    diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
    index a6f907ee7ee..be1078e09ee 100644
    --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp
    +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
    @@ -145,8 +145,8 @@ class MacroAssembler: public Assembler {
             op == 0xE9 /* jmp */ ||
             op == 0xEB /* short jmp */ ||
             (op & 0xF0) == 0x70 /* short jcc */ ||
    -        op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */ ||
    -        op == 0xC7 && branch[1] == 0xF8 /* xbegin */,
    +        (op == 0x0F && (branch[1] & 0xF0) == 0x80) /* jcc */ ||
    +        (op == 0xC7 && branch[1] == 0xF8) /* xbegin */,
             "Invalid opcode at patch point");
     
         if (op == 0xEB || (op & 0xF0) == 0x70) {
    @@ -860,23 +860,6 @@ class MacroAssembler: public Assembler {
     
       void cmpxchgptr(Register reg, Address adr);
     
    -
    -  // cvt instructions
    -  void cvtss2sd(XMMRegister dst, XMMRegister src);
    -  void cvtss2sd(XMMRegister dst, Address src);
    -  void cvtsd2ss(XMMRegister dst, XMMRegister src);
    -  void cvtsd2ss(XMMRegister dst, Address src);
    -  void cvtsi2sdl(XMMRegister dst, Register src);
    -  void cvtsi2sdl(XMMRegister dst, Address src);
    -  void cvtsi2ssl(XMMRegister dst, Register src);
    -  void cvtsi2ssl(XMMRegister dst, Address src);
    -#ifdef _LP64
    -  void cvtsi2sdq(XMMRegister dst, Register src);
    -  void cvtsi2sdq(XMMRegister dst, Address src);
    -  void cvtsi2ssq(XMMRegister dst, Register src);
    -  void cvtsi2ssq(XMMRegister dst, Address src);
    -#endif
    -
       void locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch = noreg);
     
       void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); }
    diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp
    index bc249c0f33a..de844c4be9f 100644
    --- a/src/hotspot/cpu/x86/matcher_x86.hpp
    +++ b/src/hotspot/cpu/x86/matcher_x86.hpp
    @@ -248,4 +248,17 @@
         }
       }
     
    +  // Is SIMD sort supported for this CPU?
    +  static bool supports_simd_sort(BasicType bt) {
    +    if (VM_Version::supports_avx512dq()) {
    +      return true;
    +    }
    +    else if (VM_Version::supports_avx2() && !is_double_word_type(bt)) {
    +      return true;
    +    }
    +    else {
    +      return false;
    +    }
    +  }
    +
     #endif // CPU_X86_MATCHER_X86_HPP
    diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp
    index 1df8c78c99d..b59f4246256 100644
    --- a/src/hotspot/cpu/x86/nativeInst_x86.cpp
    +++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp
    @@ -684,10 +684,15 @@ void NativePostCallNop::make_deopt() {
       ICache::invalidate_range(instr_addr, instruction_size);
     }
     
    -void NativePostCallNop::patch(jint diff) {
    -  assert(diff != 0, "must be");
    +bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
    +  if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) {
    +    return false; // cannot encode
    +  }
    +  int32_t data = (oopmap_slot << 24) | cb_offset;
    +  assert(data != 0, "must be");
       int32_t *code_pos = (int32_t *) addr_at(displacement_offset);
    -  *((int32_t *)(code_pos)) = (int32_t) diff;
    +  *((int32_t *)(code_pos)) = (int32_t) data;
    +  return true; // successfully encoded
     }
     
     void NativeDeoptInstruction::verify() {
    diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp
    index 938a10cb63d..f8cbf70f189 100644
    --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp
    +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp
    @@ -735,8 +735,16 @@ class NativePostCallNop: public NativeInstruction {
       };
     
       bool check() const { return int_at(0) == 0x841f0f; }
    -  int displacement() const { return (jint) int_at(displacement_offset); }
    -  void patch(jint diff);
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
    +    int32_t data = int_at(displacement_offset);
    +    if (data == 0) {
    +      return false; // no information encoded
    +    }
    +    cb_offset = (data & 0xffffff);
    +    oopmap_slot = (data >> 24) & 0xff;
    +    return true; // decoding succeeded
    +  }
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset);
       void make_deopt();
     };
     
    diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
    index 1d410a2f42b..298f652e971 100644
    --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
    +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
    @@ -528,8 +528,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
         }
       }
     
    -  // return value can be odd number of VMRegImpl stack slots make multiple of 2
    -  return align_up(stack, 2);
    +  return stack;
     }
     
     const uint SharedRuntime::java_return_convention_max_int = 1;
    diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
    index f6da06f9415..3ff7f7cb676 100644
    --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
    +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
    @@ -499,7 +499,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
     
       uint int_args = 0;
       uint fp_args = 0;
    -  uint stk_args = 0; // inc by 2 each time
    +  uint stk_args = 0;
     
       for (int i = 0; i < total_args_passed; i++) {
         switch (sig_bt[i]) {
    @@ -511,8 +511,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (int_args < Argument::n_int_register_parameters_j) {
             regs[i].set1(INT_ArgReg[int_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set1(VMRegImpl::stack2reg(stk_args));
    -        stk_args += 2;
    +        stk_args += 1;
           }
           break;
         case T_VOID:
    @@ -529,6 +530,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (int_args < Argument::n_int_register_parameters_j) {
             regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set2(VMRegImpl::stack2reg(stk_args));
             stk_args += 2;
           }
    @@ -537,8 +539,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (fp_args < Argument::n_float_register_parameters_j) {
             regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set1(VMRegImpl::stack2reg(stk_args));
    -        stk_args += 2;
    +        stk_args += 1;
           }
           break;
         case T_DOUBLE:
    @@ -546,6 +549,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
           if (fp_args < Argument::n_float_register_parameters_j) {
             regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg());
           } else {
    +        stk_args = align_up(stk_args, 2);
             regs[i].set2(VMRegImpl::stack2reg(stk_args));
             stk_args += 2;
           }
    @@ -556,7 +560,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
         }
       }
     
    -  return align_up(stk_args, 2);
    +  return stk_args;
     }
     
     // Same as java_calling_convention() but for multiple return
    diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
    index 9363f369037..4adccff65cb 100644
    --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
    +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -2334,7 +2334,7 @@ address StubGenerator::generate_base64_decodeBlock() {
       const Register isURL = c_rarg5;// Base64 or URL character set
       __ movl(isMIME, Address(rbp, 2 * wordSize));
     #else
    -  const Address  dp_mem(rbp, 6 * wordSize);  // length is on stack on Win64
    +  const Address dp_mem(rbp, 6 * wordSize);  // length is on stack on Win64
       const Address isURL_mem(rbp, 7 * wordSize);
       const Register isURL = r10;      // pick the volatile windows register
       const Register dp = r12;
    @@ -2556,10 +2556,12 @@ address StubGenerator::generate_base64_decodeBlock() {
         // output_size in r13
     
         // Strip pad characters, if any, and adjust length and mask
    +    __ addq(length, start_offset);
         __ cmpb(Address(source, length, Address::times_1, -1), '=');
         __ jcc(Assembler::equal, L_padding);
     
         __ BIND(L_donePadding);
    +    __ subq(length, start_offset);
     
         // Output size is (64 - output_size), output mask is (all 1s >> output_size).
         __ kmovql(input_mask, rax);
    @@ -4363,22 +4365,23 @@ void StubGenerator::generate_compiler_stubs() {
           = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square);
       }
     
    -  // Load x86_64_sort library on supported hardware to enable avx512 sort and partition intrinsics
    -  if (VM_Version::is_intel() && VM_Version::supports_avx512dq()) {
    +  // Load x86_64_sort library on supported hardware to enable SIMD sort and partition intrinsics
    +
    +  if (VM_Version::is_intel() && (VM_Version::supports_avx512dq() || VM_Version::supports_avx2())) {
         void *libsimdsort = nullptr;
         char ebuf_[1024];
         char dll_name_simd_sort[JVM_MAXPATHLEN];
         if (os::dll_locate_lib(dll_name_simd_sort, sizeof(dll_name_simd_sort), Arguments::get_dll_dir(), "simdsort")) {
           libsimdsort = os::dll_load(dll_name_simd_sort, ebuf_, sizeof ebuf_);
         }
    -    // Get addresses for avx512 sort and partition routines
    +    // Get addresses for SIMD sort and partition routines
         if (libsimdsort != nullptr) {
           log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "simdsort" JNI_LIB_SUFFIX, p2i(libsimdsort));
     
    -      snprintf(ebuf_, sizeof(ebuf_), "avx512_sort");
    +      snprintf(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512dq() ? "avx512_sort" : "avx2_sort");
           StubRoutines::_array_sort = (address)os::dll_lookup(libsimdsort, ebuf_);
     
    -      snprintf(ebuf_, sizeof(ebuf_), "avx512_partition");
    +      snprintf(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512dq() ? "avx512_partition" : "avx2_partition");
           StubRoutines::_array_partition = (address)os::dll_lookup(libsimdsort, ebuf_);
         }
       }
    diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp
    index 3aba20498d9..f4d22aaf9ce 100644
    --- a/src/hotspot/cpu/x86/templateTable_x86.cpp
    +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp
    @@ -4339,9 +4339,14 @@ void TemplateTable::_new() {
       // get InstanceKlass
       __ load_resolved_klass_at_index(rcx, rcx, rdx);
     
    -  // make sure klass is initialized & doesn't have finalizer
    +  // make sure klass is initialized
    +#ifdef _LP64
    +  assert(VM_Version::supports_fast_class_init_checks(), "must support fast class initialization checks");
    +  __ clinit_barrier(rcx, r15_thread, nullptr /*L_fast_path*/, &slow_case);
    +#else
       __ cmpb(Address(rcx, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
       __ jcc(Assembler::notEqual, slow_case);
    +#endif
     
       __ allocate_instance(rcx, rax, rdx, rbx, true, slow_case);
       __ jmp(done);
    diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
    index c8e633eff25..a5e0ab72102 100644
    --- a/src/hotspot/cpu/x86/vm_version_x86.cpp
    +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -858,7 +858,7 @@ void VM_Version::get_processor_features() {
     
       // Check if processor has Intel Ecore
       if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && cpu_family() == 6 &&
    -    (_model == 0x97 || _model == 0xAC || _model == 0xAF)) {
    +    (_model == 0x97 || _model == 0xAA || _model == 0xAC || _model == 0xAF)) {
         FLAG_SET_DEFAULT(EnableX86ECoreOpts, true);
       }
     
    @@ -1130,6 +1130,7 @@ void VM_Version::get_processor_features() {
         FLAG_SET_DEFAULT(UseGHASHIntrinsics, false);
       }
     
    +#ifdef _LP64
       // ChaCha20 Intrinsics
       // As long as the system supports AVX as a baseline we can do a
       // SIMD-enabled block function.  StubGenerator makes the determination
    @@ -1145,6 +1146,13 @@ void VM_Version::get_processor_features() {
           }
           FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false);
       }
    +#else
    +  // No support currently for ChaCha20 intrinsics on 32-bit platforms
    +  if (UseChaCha20Intrinsics) {
    +      warning("ChaCha20 intrinsics are not available on this CPU.");
    +      FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false);
    +  }
    +#endif // _LP64
     
       // Base64 Intrinsics (Check the condition for which the intrinsic will be active)
       if (UseAVX >= 2) {
    @@ -1170,7 +1178,7 @@ void VM_Version::get_processor_features() {
         UseMD5Intrinsics = true;
       }
     
    -  if (supports_sha() LP64_ONLY(|| supports_avx2() && supports_bmi2())) {
    +  if (supports_sha() LP64_ONLY(|| (supports_avx2() && supports_bmi2()))) {
         if (FLAG_IS_DEFAULT(UseSHA)) {
           UseSHA = true;
         }
    diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp
    index 454a8f31255..e521a6ee3bc 100644
    --- a/src/hotspot/cpu/x86/vm_version_x86.hpp
    +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp
    @@ -756,7 +756,7 @@ class VM_Version : public Abstract_VM_Version {
       // the intrinsic for java.lang.Thread.onSpinWait()
       static bool supports_on_spin_wait() { return supports_sse2(); }
     
    -  // x86_64 supports fast class initialization checks for static methods.
    +  // x86_64 supports fast class initialization checks
       static bool supports_fast_class_init_checks() {
         return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32
       }
    diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
    index 72070625638..d5b03610282 100644
    --- a/src/hotspot/cpu/x86/x86.ad
    +++ b/src/hotspot/cpu/x86/x86.ad
    @@ -1,5 +1,5 @@
     //
    -// Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
    +// Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
     // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     //
     // This code is free software; you can redistribute it and/or modify it
    @@ -2532,8 +2532,8 @@ static inline Assembler::ComparisonPredicateFP booltest_pred_to_comparison_pred_
     static void vec_mov_helper(CodeBuffer *cbuf, int src_lo, int dst_lo,
                               int src_hi, int dst_hi, uint ireg, outputStream* st) {
       assert(ireg == Op_VecS || // 32bit vector
    -         (src_lo & 1) == 0 && (src_lo + 1) == src_hi &&
    -         (dst_lo & 1) == 0 && (dst_lo + 1) == dst_hi,
    +         ((src_lo & 1) == 0 && (src_lo + 1) == src_hi &&
    +          (dst_lo & 1) == 0 && (dst_lo + 1) == dst_hi),
              "no non-adjacent vector moves" );
       if (cbuf) {
         C2_MacroAssembler _masm(cbuf);
    @@ -4087,39 +4087,26 @@ instruct gather(legVec dst, memory mem, legVec idx, rRegP tmp, legVec mask) %{
       effect(TEMP dst, TEMP tmp, TEMP mask);
       format %{ "load_vector_gather $dst, $mem, $idx\t! using $tmp and $mask as TEMP" %}
       ins_encode %{
    -    assert(UseAVX >= 2, "sanity");
    -
         int vlen_enc = vector_length_encoding(this);
         BasicType elem_bt = Matcher::vector_element_basic_type(this);
    -
    -    assert(Matcher::vector_length_in_bytes(this) >= 16, "sanity");
         assert(!is_subword_type(elem_bt), "sanity"); // T_INT, T_LONG, T_FLOAT, T_DOUBLE
    -
    -    if (vlen_enc == Assembler::AVX_128bit) {
    -      __ movdqu($mask$$XMMRegister, ExternalAddress(vector_all_bits_set()), noreg);
    -    } else {
    -      __ vmovdqu($mask$$XMMRegister, ExternalAddress(vector_all_bits_set()), noreg);
    -    }
    +    __ vpcmpeqd($mask$$XMMRegister, $mask$$XMMRegister, $mask$$XMMRegister, vlen_enc);
         __ lea($tmp$$Register, $mem$$Address);
         __ vgather(elem_bt, $dst$$XMMRegister, $tmp$$Register, $idx$$XMMRegister, $mask$$XMMRegister, vlen_enc);
       %}
       ins_pipe( pipe_slow );
     %}
     
    +
     instruct evgather(vec dst, memory mem, vec idx, rRegP tmp, kReg ktmp) %{
       predicate(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64);
       match(Set dst (LoadVectorGather mem idx));
       effect(TEMP dst, TEMP tmp, TEMP ktmp);
       format %{ "load_vector_gather $dst, $mem, $idx\t! using $tmp and ktmp as TEMP" %}
       ins_encode %{
    -    assert(UseAVX > 2, "sanity");
    -
         int vlen_enc = vector_length_encoding(this);
         BasicType elem_bt = Matcher::vector_element_basic_type(this);
    -
    -    assert(!is_subword_type(elem_bt), "sanity"); // T_INT, T_LONG, T_FLOAT, T_DOUBLE
    -
    -    __ kmovwl($ktmp$$KRegister, ExternalAddress(vector_all_bits_set()), noreg);
    +    __ kxnorwl($ktmp$$KRegister, $ktmp$$KRegister, $ktmp$$KRegister);
         __ lea($tmp$$Register, $mem$$Address);
         __ evgather(elem_bt, $dst$$XMMRegister, $ktmp$$KRegister, $tmp$$Register, $idx$$XMMRegister, vlen_enc);
       %}
    @@ -4127,6 +4114,7 @@ instruct evgather(vec dst, memory mem, vec idx, rRegP tmp, kReg ktmp) %{
     %}
     
     instruct evgather_masked(vec dst, memory mem, vec idx, kReg mask, kReg ktmp, rRegP tmp) %{
    +  predicate(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64);
       match(Set dst (LoadVectorGatherMasked mem (Binary idx mask)));
       effect(TEMP_DEF dst, TEMP tmp, TEMP ktmp);
       format %{ "load_vector_gather_masked $dst, $mem, $idx, $mask\t! using $tmp and ktmp as TEMP" %}
    @@ -9011,6 +8999,21 @@ instruct vmasked_store_evex(memory mem, vec src, kReg mask) %{
     %}
     
     #ifdef _LP64
    +instruct verify_vector_alignment(rRegP addr, immL32 mask, rFlagsReg cr) %{
    +  match(Set addr (VerifyVectorAlignment addr mask));
    +  effect(KILL cr);
    +  format %{ "verify_vector_alignment $addr $mask \t! verify alignment" %}
    +  ins_encode %{
    +    Label Lskip;
    +    // check if masked bits of addr are zero
    +    __ testq($addr$$Register, $mask$$constant);
    +    __ jccb(Assembler::equal, Lskip);
    +    __ stop("verify_vector_alignment found a misaligned vector memory access");
    +    __ bind(Lskip);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
     instruct vmask_cmp_node(rRegI dst, vec src1, vec src2, kReg mask, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{
       match(Set dst (VectorCmpMasked src1 (Binary src2 mask)));
       effect(TEMP_DEF dst, TEMP ktmp1, TEMP ktmp2, KILL cr);
    diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad
    index 17b1aea0e51..5a3012f3d81 100644
    --- a/src/hotspot/cpu/x86/x86_32.ad
    +++ b/src/hotspot/cpu/x86/x86_32.ad
    @@ -1,5 +1,5 @@
     //
    -// Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
    +// Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
     // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     //
     // This code is free software; you can redistribute it and/or modify it
    @@ -11139,7 +11139,7 @@ instruct convI2FPR_mem(regFPR dst, memory mem) %{
     
     // Convert an int to a float in xmm; no rounding step needed.
     instruct convI2F_reg(regF dst, rRegI src) %{
    -  predicate( UseSSE==1 || UseSSE>=2 && !UseXmmI2F );
    +  predicate( UseSSE==1 || ( UseSSE>=2 && !UseXmmI2F ));
       match(Set dst (ConvI2F src));
       format %{ "CVTSI2SS $dst, $src" %}
       ins_encode %{
    @@ -13158,7 +13158,7 @@ instruct cmovPP_reg_LTGE_U(cmpOpU cmp, flagsReg_ulong_LTGE flags, eRegP dst, eRe
     
     // Compare 2 longs and CMOVE doubles
     instruct cmovDDPR_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regDPR dst, regDPR src) %{
    -  predicate( UseSSE<=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
    +  predicate( UseSSE<=1 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ));
       match(Set dst (CMoveD (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13168,7 +13168,7 @@ instruct cmovDDPR_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regDPR dst, regD
     
     // Compare 2 longs and CMOVE doubles
     instruct cmovDD_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regD dst, regD src) %{
    -  predicate( UseSSE>=2 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
    +  predicate( UseSSE>=2 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ));
       match(Set dst (CMoveD (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13177,7 +13177,7 @@ instruct cmovDD_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regD dst, regD src
     %}
     
     instruct cmovFFPR_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regFPR dst, regFPR src) %{
    -  predicate( UseSSE==0 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
    +  predicate( UseSSE==0 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ));
       match(Set dst (CMoveF (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13186,7 +13186,7 @@ instruct cmovFFPR_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regFPR dst, regF
     %}
     
     instruct cmovFF_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regF dst, regF src) %{
    -  predicate( UseSSE>=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
    +  predicate( UseSSE>=1 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ));
       match(Set dst (CMoveF (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13349,7 +13349,7 @@ instruct cmovPP_reg_EQNE_U(cmpOpU cmp, flagsReg_ulong_EQNE flags, eRegP dst, eRe
     
     // Compare 2 longs and CMOVE doubles
     instruct cmovDDPR_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regDPR dst, regDPR src) %{
    -  predicate( UseSSE<=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
    +  predicate( UseSSE<=1 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ));
       match(Set dst (CMoveD (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13359,7 +13359,7 @@ instruct cmovDDPR_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regDPR dst, regD
     
     // Compare 2 longs and CMOVE doubles
     instruct cmovDD_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regD dst, regD src) %{
    -  predicate( UseSSE>=2 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
    +  predicate( UseSSE>=2 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ));
       match(Set dst (CMoveD (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13368,7 +13368,7 @@ instruct cmovDD_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regD dst, regD src
     %}
     
     instruct cmovFFPR_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regFPR dst, regFPR src) %{
    -  predicate( UseSSE==0 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
    +  predicate( UseSSE==0 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ));
       match(Set dst (CMoveF (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13377,7 +13377,7 @@ instruct cmovFFPR_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regFPR dst, regF
     %}
     
     instruct cmovFF_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regF dst, regF src) %{
    -  predicate( UseSSE>=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
    +  predicate( UseSSE>=1 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ));
       match(Set dst (CMoveF (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13568,7 +13568,7 @@ instruct cmovPP_reg_LEGT_U(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, eRegP
     
     // Compare 2 longs and CMOVE doubles
     instruct cmovDDPR_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regDPR dst, regDPR src) %{
    -  predicate( UseSSE<=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
    +  predicate( UseSSE<=1 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ));
       match(Set dst (CMoveD (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13578,7 +13578,7 @@ instruct cmovDDPR_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regDPR d
     
     // Compare 2 longs and CMOVE doubles
     instruct cmovDD_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regD dst, regD src) %{
    -  predicate( UseSSE>=2 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
    +  predicate( UseSSE>=2 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ));
       match(Set dst (CMoveD (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13587,7 +13587,7 @@ instruct cmovDD_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regD dst,
     %}
     
     instruct cmovFFPR_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regFPR dst, regFPR src) %{
    -  predicate( UseSSE==0 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
    +  predicate( UseSSE==0 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ));
       match(Set dst (CMoveF (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    @@ -13597,7 +13597,7 @@ instruct cmovFFPR_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regFPR d
     
     
     instruct cmovFF_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regF dst, regF src) %{
    -  predicate( UseSSE>=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
    +  predicate( UseSSE>=1 && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ));
       match(Set dst (CMoveF (Binary cmp flags) (Binary dst src)));
       ins_cost(200);
       expand %{
    diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
    index d1965f88d2d..19997636412 100644
    --- a/src/hotspot/cpu/x86/x86_64.ad
    +++ b/src/hotspot/cpu/x86/x86_64.ad
    @@ -10139,7 +10139,7 @@ instruct cmpD_imm(rRegI dst, regD src, immD con, rFlagsReg cr) %{
     instruct convF2D_reg_reg(regD dst, regF src)
     %{
       match(Set dst (ConvF2D src));
    -  effect(TEMP dst);
    +
       format %{ "cvtss2sd $dst, $src" %}
       ins_encode %{
         __ cvtss2sd ($dst$$XMMRegister, $src$$XMMRegister);
    @@ -10161,7 +10161,7 @@ instruct convF2D_reg_mem(regD dst, memory src)
     instruct convD2F_reg_reg(regF dst, regD src)
     %{
       match(Set dst (ConvD2F src));
    -  effect(TEMP dst);
    +
       format %{ "cvtsd2ss $dst, $src" %}
       ins_encode %{
         __ cvtsd2ss ($dst$$XMMRegister, $src$$XMMRegister);
    diff --git a/src/hotspot/cpu/zero/frame_zero.hpp b/src/hotspot/cpu/zero/frame_zero.hpp
    index 87511ab212e..a4815d2c10b 100644
    --- a/src/hotspot/cpu/zero/frame_zero.hpp
    +++ b/src/hotspot/cpu/zero/frame_zero.hpp
    @@ -44,8 +44,6 @@
         align_wiggle     =  1
       };
     
    - const ImmutableOopMap* get_oop_map() const;
    -
       // Constructor
      public:
       frame(ZeroFrame* zeroframe, intptr_t* sp);
    diff --git a/src/hotspot/cpu/zero/frame_zero.inline.hpp b/src/hotspot/cpu/zero/frame_zero.inline.hpp
    index 1b504cfa666..944084f70af 100644
    --- a/src/hotspot/cpu/zero/frame_zero.inline.hpp
    +++ b/src/hotspot/cpu/zero/frame_zero.inline.hpp
    @@ -176,11 +176,6 @@ inline intptr_t* frame::unextended_sp() const {
       return (intptr_t *) -1;
     }
     
    -inline const ImmutableOopMap* frame::get_oop_map() const {
    -  Unimplemented();
    -  return nullptr;
    -}
    -
     inline int frame::compiled_frame_stack_argsize() const {
       Unimplemented();
       return 0;
    diff --git a/src/hotspot/cpu/zero/globalDefinitions_zero.hpp b/src/hotspot/cpu/zero/globalDefinitions_zero.hpp
    index 810f7de3cb3..0f78b3eeefb 100644
    --- a/src/hotspot/cpu/zero/globalDefinitions_zero.hpp
    +++ b/src/hotspot/cpu/zero/globalDefinitions_zero.hpp
    @@ -30,8 +30,12 @@
     #define SUPPORTS_NATIVE_CX8
     #endif
     
    +// The expected size in bytes of a cache line.
     #define DEFAULT_CACHE_LINE_SIZE 64
     
    +// The default padding size for data structures to avoid false sharing.
    +#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
    +
     #define SUPPORT_MONITOR_COUNT
     
     #include 
    diff --git a/src/hotspot/cpu/zero/nativeInst_zero.hpp b/src/hotspot/cpu/zero/nativeInst_zero.hpp
    index 5b2c9743cf9..77a7d511ac5 100644
    --- a/src/hotspot/cpu/zero/nativeInst_zero.hpp
    +++ b/src/hotspot/cpu/zero/nativeInst_zero.hpp
    @@ -214,8 +214,8 @@ inline NativeGeneralJump* nativeGeneralJump_at(address address) {
     class NativePostCallNop: public NativeInstruction {
     public:
       bool check() const { Unimplemented(); return false; }
    -  int displacement() const { Unimplemented(); return 0; }
    -  void patch(jint diff) { Unimplemented(); }
    +  bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const { Unimplemented(); return false; }
    +  bool patch(int32_t oopmap_slot, int32_t cb_offset) { Unimplemented(); return false; }
       void make_deopt() { Unimplemented(); }
     };
     
    diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
    index 54c538cf367..c75828c0c22 100644
    --- a/src/hotspot/os/aix/os_aix.cpp
    +++ b/src/hotspot/os/aix/os_aix.cpp
    @@ -2112,11 +2112,6 @@ bool os::can_commit_large_page_memory() {
       return false;
     }
     
    -bool os::can_execute_large_page_memory() {
    -  // Does not matter, we do not support huge pages.
    -  return false;
    -}
    -
     char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
       assert(file_desc >= 0, "file_desc is not valid");
       char* result = nullptr;
    diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
    index 18f3cd2b38d..2f7f31157e8 100644
    --- a/src/hotspot/os/bsd/os_bsd.cpp
    +++ b/src/hotspot/os/bsd/os_bsd.cpp
    @@ -979,7 +979,7 @@ bool os::dll_address_to_library_name(address addr, char* buf,
     // in case of error it checks if .dll/.so was built for the
     // same architecture as Hotspot is running on
     
    -void *os::Bsd::dlopen_helper(const char *filename, int mode) {
    +void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebuflen) {
     #ifndef IA32
       bool ieee_handling = IEEE_subnormal_handling_OK();
       if (!ieee_handling) {
    @@ -1005,27 +1005,44 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode) {
       assert(rtn == 0, "fegetenv must succeed");
     #endif // IA32
     
    -  void * result= ::dlopen(filename, RTLD_LAZY);
    -
    +  void* result;
    +  JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
    +  result = ::dlopen(filename, RTLD_LAZY);
    +  if (result == nullptr) {
    +    const char* error_report = ::dlerror();
    +    if (error_report == nullptr) {
    +      error_report = "dlerror returned no error description";
    +    }
    +    if (ebuf != nullptr && ebuflen > 0) {
    +      ::strncpy(ebuf, error_report, ebuflen-1);
    +      ebuf[ebuflen-1]='\0';
    +    }
    +    Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
    +    log_info(os)("shared library load of %s failed, %s", filename, error_report);
    +    JFR_ONLY(load_event.set_error_msg(error_report);)
    +  } else {
    +    Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
    +    log_info(os)("shared library load of %s was successful", filename);
     #ifndef IA32
    -  if (result  != nullptr && ! IEEE_subnormal_handling_OK()) {
    -    // We just dlopen()ed a library that mangled the floating-point
    -    // flags. Silently fix things now.
    -    int rtn = fesetenv(&default_fenv);
    -    assert(rtn == 0, "fesetenv must succeed");
    -    bool ieee_handling_after_issue = IEEE_subnormal_handling_OK();
    -
    -    if (ieee_handling_after_issue) {
    -      Events::log_dll_message(nullptr, "IEEE subnormal handling had to be corrected after loading %s", filename);
    -      log_info(os)("IEEE subnormal handling had to be corrected after loading %s", filename);
    -    } else {
    -      Events::log_dll_message(nullptr, "IEEE subnormal handling could not be corrected after loading %s", filename);
    -      log_info(os)("IEEE subnormal handling could not be corrected after loading %s", filename);
    +    if (! IEEE_subnormal_handling_OK()) {
    +      // We just dlopen()ed a library that mangled the floating-point
    +      // flags. Silently fix things now.
    +      JFR_ONLY(load_event.set_fp_env_correction_attempt(true);)
    +      int rtn = fesetenv(&default_fenv);
    +      assert(rtn == 0, "fesetenv must succeed");
    +
    +      if (IEEE_subnormal_handling_OK()) {
    +        Events::log_dll_message(nullptr, "IEEE subnormal handling had to be corrected after loading %s", filename);
    +        log_info(os)("IEEE subnormal handling had to be corrected after loading %s", filename);
    +        JFR_ONLY(load_event.set_fp_env_correction_success(true);)
    +      } else {
    +        Events::log_dll_message(nullptr, "IEEE subnormal handling could not be corrected after loading %s", filename);
    +        log_info(os)("IEEE subnormal handling could not be corrected after loading %s", filename);
    +        assert(false, "fesetenv didn't work");
    +      }
         }
    -
    -    assert(ieee_handling_after_issue, "fesetenv didn't work");
    -  }
     #endif // IA32
    +  }
     
       return result;
     }
    @@ -1037,30 +1054,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
     #else
       log_info(os)("attempting shared library load of %s", filename);
     
    -  void* result;
    -  JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
    -  result = os::Bsd::dlopen_helper(filename, RTLD_LAZY);
    -  if (result != nullptr) {
    -    Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
    -    // Successful loading
    -    log_info(os)("shared library load of %s was successful", filename);
    -    return result;
    -  }
    -
    -  const char* error_report = ::dlerror();
    -  if (error_report == nullptr) {
    -    error_report = "dlerror returned no error description";
    -  }
    -  if (ebuf != nullptr && ebuflen > 0) {
    -    // Read system error message into ebuf
    -    ::strncpy(ebuf, error_report, ebuflen-1);
    -    ebuf[ebuflen-1]='\0';
    -  }
    -  Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
    -  log_info(os)("shared library load of %s failed, %s", filename, error_report);
    -  JFR_ONLY(load_event.set_error_msg(error_report);)
    -
    -  return nullptr;
    +  return os::Bsd::dlopen_helper(filename, RTLD_LAZY, ebuf, ebuflen);
     #endif // STATIC_BUILD
     }
     #else
    @@ -1071,29 +1065,13 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
       log_info(os)("attempting shared library load of %s", filename);
     
       void* result;
    -  JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
    -  result = os::Bsd::dlopen_helper(filename, RTLD_LAZY);
    +  result = os::Bsd::dlopen_helper(filename, RTLD_LAZY, ebuf, ebuflen);
       if (result != nullptr) {
    -    Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
    -    // Successful loading
    -    log_info(os)("shared library load of %s was successful", filename);
         return result;
       }
     
    -  Elf32_Ehdr elf_head;
    -
    -  const char* const error_report = ::dlerror();
    -  if (error_report == nullptr) {
    -    error_report = "dlerror returned no error description";
    -  }
    -  if (ebuf != nullptr && ebuflen > 0) {
    -    // Read system error message into ebuf
    -    ::strncpy(ebuf, error_report, ebuflen-1);
    -    ebuf[ebuflen-1]='\0';
    -  }
       Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
       log_info(os)("shared library load of %s failed, %s", filename, error_report);
    -  JFR_ONLY(load_event.set_error_msg(error_report);)
       int diag_msg_max_length=ebuflen-strlen(ebuf);
       char* diag_msg_buf=ebuf+strlen(ebuf);
     
    @@ -1102,7 +1080,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
         return nullptr;
       }
     
    -
       int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK);
     
       if (file_descriptor < 0) {
    @@ -1110,6 +1087,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
         return nullptr;
       }
     
    +  Elf32_Ehdr elf_head;
       bool failed_to_read_elf_head=
         (sizeof(elf_head)!=
          (::read(file_descriptor, &elf_head,sizeof(elf_head))));
    @@ -1809,11 +1787,6 @@ bool os::can_commit_large_page_memory() {
       return false;
     }
     
    -bool os::can_execute_large_page_memory() {
    -  // Does not matter, we do not support huge pages.
    -  return false;
    -}
    -
     char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
       assert(file_desc >= 0, "file_desc is not valid");
       char* result = pd_attempt_reserve_memory_at(requested_addr, bytes, !ExecMem);
    diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp
    index f79212bc43c..72de9ca5971 100644
    --- a/src/hotspot/os/bsd/os_bsd.hpp
    +++ b/src/hotspot/os/bsd/os_bsd.hpp
    @@ -70,7 +70,7 @@ class os::Bsd {
       // Real-time clock functions
       static void clock_init(void);
     
    -  static void *dlopen_helper(const char *path, int mode);
    +  static void *dlopen_helper(const char *path, int mode, char *ebuf, int ebuflen);
     
       // Stack repair handling
     
    diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
    index 6c5470445f1..3cc2141f176 100644
    --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
    +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
    @@ -266,6 +266,8 @@ class CgroupSubsystem: public CHeapObj {
         virtual jlong memory_and_swap_limit_in_bytes() = 0;
         virtual jlong memory_soft_limit_in_bytes() = 0;
         virtual jlong memory_max_usage_in_bytes() = 0;
    +    virtual jlong rss_usage_in_bytes() = 0;
    +    virtual jlong cache_usage_in_bytes() = 0;
     
         virtual char * cpu_cpuset_cpus() = 0;
         virtual char * cpu_cpuset_memory_nodes() = 0;
    diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
    index 146d7237a90..37a1f476bde 100644
    --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
    +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
    @@ -214,6 +214,17 @@ jlong CgroupV1Subsystem::memory_max_usage_in_bytes() {
       return memmaxusage;
     }
     
    +jlong CgroupV1Subsystem::rss_usage_in_bytes() {
    +  GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat",
    +                          "rss", JULONG_FORMAT, JULONG_FORMAT, rss);
    +  return rss;
    +}
    +
    +jlong CgroupV1Subsystem::cache_usage_in_bytes() {
    +  GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat",
    +                          "cache", JULONG_FORMAT, JULONG_FORMAT, cache);
    +  return cache;
    +}
     
     jlong CgroupV1Subsystem::kernel_memory_usage_in_bytes() {
       GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.usage_in_bytes",
    diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
    index fae65da2a58..c7550136f48 100644
    --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
    +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
    @@ -79,6 +79,8 @@ class CgroupV1Subsystem: public CgroupSubsystem {
         jlong memory_soft_limit_in_bytes();
         jlong memory_usage_in_bytes();
         jlong memory_max_usage_in_bytes();
    +    jlong rss_usage_in_bytes();
    +    jlong cache_usage_in_bytes();
     
         jlong kernel_memory_usage_in_bytes();
         jlong kernel_memory_limit_in_bytes();
    diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
    index 1a02bbe95d2..1c433be1c23 100644
    --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
    +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
    @@ -139,6 +139,18 @@ jlong CgroupV2Subsystem::memory_max_usage_in_bytes() {
       return OSCONTAINER_ERROR; // not supported
     }
     
    +jlong CgroupV2Subsystem::rss_usage_in_bytes() {
    +  GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat",
    +                          "anon", JULONG_FORMAT, JULONG_FORMAT, rss);
    +  return rss;
    +}
    +
    +jlong CgroupV2Subsystem::cache_usage_in_bytes() {
    +  GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat",
    +                          "file", JULONG_FORMAT, JULONG_FORMAT, cache);
    +  return cache;
    +}
    +
     char* CgroupV2Subsystem::mem_soft_limit_val() {
       GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.low",
                              "Memory Soft Limit is: %s", "%1023s", mem_soft_limit_str, 1024);
    diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
    index bb6b538c216..b12b4ce6512 100644
    --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
    +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
    @@ -78,6 +78,8 @@ class CgroupV2Subsystem: public CgroupSubsystem {
         jlong memory_soft_limit_in_bytes();
         jlong memory_usage_in_bytes();
         jlong memory_max_usage_in_bytes();
    +    jlong rss_usage_in_bytes();
    +    jlong cache_usage_in_bytes();
     
         char * cpu_cpuset_cpus();
         char * cpu_cpuset_memory_nodes();
    diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp
    index c70c96c678a..14bfa5a7678 100644
    --- a/src/hotspot/os/linux/osContainer_linux.cpp
    +++ b/src/hotspot/os/linux/osContainer_linux.cpp
    @@ -92,6 +92,16 @@ jlong OSContainer::memory_max_usage_in_bytes() {
       return cgroup_subsystem->memory_max_usage_in_bytes();
     }
     
    +jlong OSContainer::rss_usage_in_bytes() {
    +  assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
    +  return cgroup_subsystem->rss_usage_in_bytes();
    +}
    +
    +jlong OSContainer::cache_usage_in_bytes() {
    +  assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
    +  return cgroup_subsystem->cache_usage_in_bytes();
    +}
    +
     void OSContainer::print_version_specific_info(outputStream* st) {
       assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
       cgroup_subsystem->print_version_specific_info(st);
    diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp
    index 776167993cb..bb03ba3b005 100644
    --- a/src/hotspot/os/linux/osContainer_linux.hpp
    +++ b/src/hotspot/os/linux/osContainer_linux.hpp
    @@ -55,6 +55,8 @@ class OSContainer: AllStatic {
       static jlong memory_soft_limit_in_bytes();
       static jlong memory_usage_in_bytes();
       static jlong memory_max_usage_in_bytes();
    +  static jlong rss_usage_in_bytes();
    +  static jlong cache_usage_in_bytes();
     
       static int active_processor_count();
     
    diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
    index 3fc025e5100..3a170edd697 100644
    --- a/src/hotspot/os/linux/os_linux.cpp
    +++ b/src/hotspot/os/linux/os_linux.cpp
    @@ -1,6 +1,6 @@
     /*
    - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
    - * Copyright (c) 2015, 2022 SAP SE. All rights reserved.
    + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2015, 2024 SAP SE. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1856,18 +1856,19 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
         if (! IEEE_subnormal_handling_OK()) {
           // We just dlopen()ed a library that mangled the floating-point flags.
           // Attempt to fix things now.
    +      JFR_ONLY(load_event.set_fp_env_correction_attempt(true);)
           int rtn = fesetenv(&default_fenv);
           assert(rtn == 0, "fesetenv must succeed");
    -      bool ieee_handling_after_issue = IEEE_subnormal_handling_OK();
     
    -      if (ieee_handling_after_issue) {
    +      if (IEEE_subnormal_handling_OK()) {
             Events::log_dll_message(nullptr, "IEEE subnormal handling had to be corrected after loading %s", filename);
             log_info(os)("IEEE subnormal handling had to be corrected after loading %s", filename);
    +        JFR_ONLY(load_event.set_fp_env_correction_success(true);)
           } else {
             Events::log_dll_message(nullptr, "IEEE subnormal handling could not be corrected after loading %s", filename);
             log_info(os)("IEEE subnormal handling could not be corrected after loading %s", filename);
    +        assert(false, "fesetenv didn't work");
           }
    -      assert(ieee_handling_after_issue, "fesetenv didn't work");
         }
     #endif // IA32
       }
    @@ -2096,7 +2097,6 @@ const char* distro_files[] = {
       "/etc/mandrake-release",
       "/etc/sun-release",
       "/etc/redhat-release",
    -  "/etc/SuSE-release",
       "/etc/lsb-release",
       "/etc/turbolinux-release",
       "/etc/gentoo-release",
    @@ -2104,6 +2104,7 @@ const char* distro_files[] = {
       "/etc/angstrom-version",
       "/etc/system-release",
       "/etc/os-release",
    +  "/etc/SuSE-release", // Deprecated in favor of os-release since SuSE 12
       nullptr };
     
     void os::Linux::print_distro_info(outputStream* st) {
    @@ -2215,6 +2216,8 @@ void os::Linux::print_system_memory_info(outputStream* st) {
       // https://www.kernel.org/doc/Documentation/vm/transhuge.txt
       _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/enabled",
                           "/sys/kernel/mm/transparent_hugepage/enabled", st);
    +  _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size",
    +                      "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", st);
       _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/shmem_enabled",
                           "/sys/kernel/mm/transparent_hugepage/shmem_enabled", st);
       _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/defrag (defrag/compaction efforts parameter)",
    @@ -2395,6 +2398,8 @@ bool os::Linux::print_container_info(outputStream* st) {
       OSContainer::print_container_helper(st, OSContainer::memory_soft_limit_in_bytes(), "memory_soft_limit_in_bytes");
       OSContainer::print_container_helper(st, OSContainer::memory_usage_in_bytes(), "memory_usage_in_bytes");
       OSContainer::print_container_helper(st, OSContainer::memory_max_usage_in_bytes(), "memory_max_usage_in_bytes");
    +  OSContainer::print_container_helper(st, OSContainer::rss_usage_in_bytes(), "rss_usage_in_bytes");
    +  OSContainer::print_container_helper(st, OSContainer::cache_usage_in_bytes(), "cache_usage_in_bytes");
     
       OSContainer::print_version_specific_info(st);
     
    @@ -4075,10 +4080,6 @@ bool os::can_commit_large_page_memory() {
       return UseTransparentHugePages;
     }
     
    -bool os::can_execute_large_page_memory() {
    -  return UseTransparentHugePages;
    -}
    -
     char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
       assert(file_desc >= 0, "file_desc is not valid");
       char* result = pd_attempt_reserve_memory_at(requested_addr, bytes, !ExecMem);
    diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
    index 223bc0bd135..1b5c7850bf2 100644
    --- a/src/hotspot/os/windows/os_windows.cpp
    +++ b/src/hotspot/os/windows/os_windows.cpp
    @@ -3436,10 +3436,6 @@ bool os::can_commit_large_page_memory() {
       return false;
     }
     
    -bool os::can_execute_large_page_memory() {
    -  return true;
    -}
    -
     static char* reserve_large_pages_individually(size_t size, char* req_addr, bool exec) {
       log_debug(pagesize)("Reserving large pages individually.");
     
    diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp
    index df5a42fd118..fbd7c4eccd4 100644
    --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp
    +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp
    @@ -514,7 +514,39 @@ static inline void atomic_copy64(const volatile void *src, volatile void *dst) {
     
     extern "C" {
       int SpinPause() {
    -    return 0;
    +    // We don't use StubRoutines::aarch64::spin_wait stub in order to
    +    // avoid a costly call to os::current_thread_enable_wx() on MacOS.
    +    // We should return 1 if SpinPause is implemented, and since there
    +    // will be a sequence of 11 instructions for NONE and YIELD and 12
    +    // instructions for NOP and ISB, SpinPause will always return 1.
    +    uint64_t br_dst;
    +    const int instructions_per_case = 2;
    +    int64_t off = VM_Version::spin_wait_desc().inst() * instructions_per_case * Assembler::instruction_size;
    +
    +    assert(VM_Version::spin_wait_desc().inst() >= SpinWait::NONE &&
    +           VM_Version::spin_wait_desc().inst() <= SpinWait::YIELD, "must be");
    +    assert(-1 == SpinWait::NONE,  "must be");
    +    assert( 0 == SpinWait::NOP,   "must be");
    +    assert( 1 == SpinWait::ISB,   "must be");
    +    assert( 2 == SpinWait::YIELD, "must be");
    +
    +    asm volatile(
    +        "  adr  %[d], 20          \n" // 20 == PC here + 5 instructions => address
    +                                      // to entry for case SpinWait::NOP
    +        "  add  %[d], %[d], %[o]  \n"
    +        "  br   %[d]              \n"
    +        "  b    SpinPause_return  \n" // case SpinWait::NONE  (-1)
    +        "  nop                    \n" // padding
    +        "  nop                    \n" // case SpinWait::NOP   ( 0)
    +        "  b    SpinPause_return  \n"
    +        "  isb                    \n" // case SpinWait::ISB   ( 1)
    +        "  b    SpinPause_return  \n"
    +        "  yield                  \n" // case SpinWait::YIELD ( 2)
    +        "SpinPause_return:        \n"
    +        : [d]"=&r"(br_dst)
    +        : [o]"r"(off)
    +        : "memory");
    +    return 1;
       }
     
       void _Copy_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) {
    diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp
    index 8b9d1178ca5..282467bc9e0 100644
    --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp
    +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp
    @@ -232,7 +232,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
             CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr;
             bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc));
             if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) {
    -          address next_pc = pc + NativeCall::instruction_size;
    +          address next_pc = Assembler::locate_next_instruction(pc);
               if (is_unsafe_arraycopy) {
                 next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
               }
    @@ -271,7 +271,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
                     thread->thread_state() == _thread_in_native) &&
                     sig == SIGBUS && /* info->si_code == BUS_OBJERR && */
                     thread->doing_unsafe_access()) {
    -      address next_pc = pc + NativeCall::instruction_size;
    +      address next_pc = Assembler::locate_next_instruction(pc);
           if (UnsafeCopyMemory::contains_pc(pc)) {
             next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
           }
    diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
    index 6e93406b1a3..354dbd70bb4 100644
    --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
    +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
    @@ -240,6 +240,8 @@ void VM_Version::rivos_features() {
       ext_Zbb.enable_feature();
       ext_Zbs.enable_feature();
     
    +  ext_Zcb.enable_feature();
    +
       ext_Zicsr.enable_feature();
       ext_Zifencei.enable_feature();
       ext_Zic64b.enable_feature();
    diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp
    index 16e3287aa0a..d2aa573cecd 100644
    --- a/src/hotspot/share/adlc/formssel.cpp
    +++ b/src/hotspot/share/adlc/formssel.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -794,6 +794,7 @@ bool InstructForm::captures_bottom_type(FormDict &globals) const {
            !strcmp(_matrule->_rChild->_opType,"StrInflatedCopy") ||
            !strcmp(_matrule->_rChild->_opType,"VectorCmpMasked")||
            !strcmp(_matrule->_rChild->_opType,"VectorMaskGen")||
    +       !strcmp(_matrule->_rChild->_opType,"VerifyVectorAlignment")||
            !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") ||
            !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true;
       else if ( is_ideal_load() == Form::idealP )                return true;
    diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp
    index 1fac664ef1d..d94de804305 100644
    --- a/src/hotspot/share/c1/c1_Compilation.cpp
    +++ b/src/hotspot/share/c1/c1_Compilation.cpp
    @@ -33,10 +33,12 @@
     #include "c1/c1_ValueMap.hpp"
     #include "c1/c1_ValueStack.hpp"
     #include "code/debugInfoRec.hpp"
    +#include "compiler/compilationFailureInfo.hpp"
     #include "compiler/compilationMemoryStatistic.hpp"
     #include "compiler/compilerDirectives.hpp"
     #include "compiler/compileLog.hpp"
     #include "compiler/compileTask.hpp"
    +#include "compiler/compiler_globals.hpp"
     #include "compiler/compilerDirectives.hpp"
     #include "memory/resourceArea.hpp"
     #include "runtime/sharedRuntime.hpp"
    @@ -76,7 +78,6 @@ static const char * timer_name[] = {
     };
     
     static elapsedTimer timers[max_phase_timers];
    -static uint totalInstructionNodes = 0;
     
     class PhaseTraceTime: public TraceTime {
      private:
    @@ -389,10 +390,6 @@ int Compilation::compile_java_method() {
         BAILOUT_("mdo allocation failed", no_frame_size);
       }
     
    -  if (method()->is_synchronized()) {
    -    set_has_monitors(true);
    -  }
    -
       {
         PhaseTraceTime timeit(_t_buildIR);
         build_hir();
    @@ -494,7 +491,6 @@ void Compilation::compile_method() {
       if (log() != nullptr) // Print code cache state into compiler log
         log()->code_cache_state();
     
    -  totalInstructionNodes += Instruction::number_of_instructions();
     }
     
     
    @@ -581,9 +577,10 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
     , _would_profile(false)
     , _has_method_handle_invokes(false)
     , _has_reserved_stack_access(method->has_reserved_stack_access())
    -, _has_monitors(false)
    +, _has_monitors(method->is_synchronized() || method->has_monitor_bytecodes())
     , _install_code(install_code)
     , _bailout_msg(nullptr)
    +, _first_failure_details(nullptr)
     , _exception_info_list(nullptr)
     , _allocator(nullptr)
     , _code(buffer_blob)
    @@ -634,7 +631,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
     Compilation::~Compilation() {
       // simulate crash during compilation
       assert(CICrashAt < 0 || (uintx)_env->compile_id() != (uintx)CICrashAt, "just as planned");
    -
    +  delete _first_failure_details;
       _env->set_compiler_data(nullptr);
     }
     
    @@ -660,6 +657,9 @@ void Compilation::bailout(const char* msg) {
         // keep first bailout message
         if (PrintCompilation || PrintBailouts) tty->print_cr("compilation bailout: %s", msg);
         _bailout_msg = msg;
    +    if (CaptureBailoutInformation) {
    +      _first_failure_details = new CompilationFailureInfo(msg);
    +    }
       }
     }
     
    diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp
    index e3fe224270d..82b28bd69ae 100644
    --- a/src/hotspot/share/c1/c1_Compilation.hpp
    +++ b/src/hotspot/share/c1/c1_Compilation.hpp
    @@ -35,6 +35,7 @@
     #include "runtime/deoptimization.hpp"
     #include "runtime/sharedRuntime.hpp"
     
    +class CompilationFailureInfo;
     class CompilationResourceObj;
     class XHandlers;
     class ExceptionInfo;
    @@ -86,6 +87,7 @@ class Compilation: public StackObj {
       bool               _has_monitors; // Fastpath monitors detection for Continuations
       bool               _install_code;
       const char*        _bailout_msg;
    +  CompilationFailureInfo* _first_failure_details; // Details for the first failure happening during compilation
       bool               _oom;
       ExceptionInfoList* _exception_info_list;
       ExceptionHandlerTable _exception_handler_table;
    @@ -214,6 +216,7 @@ class Compilation: public StackObj {
       void bailout(const char* msg);
       bool bailed_out() const                        { return _bailout_msg != nullptr; }
       const char* bailout_msg() const                { return _bailout_msg; }
    +  const CompilationFailureInfo* first_failure_details() const { return _first_failure_details; }
     
       static uint desired_max_code_buffer_size() {
         return (uint)NMethodSizeLimit;  // default 64K
    diff --git a/src/hotspot/share/c1/c1_FrameMap.cpp b/src/hotspot/share/c1/c1_FrameMap.cpp
    index d889fa2b769..fe70c0b31f6 100644
    --- a/src/hotspot/share/c1/c1_FrameMap.cpp
    +++ b/src/hotspot/share/c1/c1_FrameMap.cpp
    @@ -72,7 +72,7 @@ CallingConvention* FrameMap::java_calling_convention(const BasicTypeArray* signa
         }
       }
     
    -  intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs);
    +  intptr_t out_preserve = align_up(SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs), 2);
       LIR_OprList* args = new LIR_OprList(signature->length());
       for (i = 0; i < sizeargs;) {
         BasicType t = sig_bt[i];
    diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp
    index acaf9cb60b2..00d03e8ef7e 100644
    --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp
    +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1416,8 +1416,8 @@ void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* sta
       Instruction *i = append(new If(x, cond, false, y, tsux, fsux, (is_bb || compilation()->is_optimistic() || subst_check) ? state_before : nullptr, is_bb, subst_check));
     
       assert(i->as_Goto() == nullptr ||
    -         (i->as_Goto()->sux_at(0) == tsux  && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) ||
    -         (i->as_Goto()->sux_at(0) == fsux  && i->as_Goto()->is_safepoint() == fsux->bci() < stream()->cur_bci()),
    +         (i->as_Goto()->sux_at(0) == tsux  && i->as_Goto()->is_safepoint() == (tsux->bci() < stream()->cur_bci())) ||
    +         (i->as_Goto()->sux_at(0) == fsux  && i->as_Goto()->is_safepoint() == (fsux->bci() < stream()->cur_bci())),
              "safepoint state of Goto returned by canonicalizer incorrect");
     
       if (is_profiling()) {
    @@ -1552,7 +1552,7 @@ void GraphBuilder::table_switch() {
         if (res->as_Goto()) {
           for (i = 0; i < l; i++) {
             if (sux->at(i) == res->as_Goto()->sux_at(0)) {
    -          assert(res->as_Goto()->is_safepoint() == sw.dest_offset_at(i) < 0, "safepoint state of Goto returned by canonicalizer incorrect");
    +          assert(res->as_Goto()->is_safepoint() == (sw.dest_offset_at(i) < 0), "safepoint state of Goto returned by canonicalizer incorrect");
             }
           }
         }
    @@ -1601,7 +1601,7 @@ void GraphBuilder::lookup_switch() {
         if (res->as_Goto()) {
           for (i = 0; i < l; i++) {
             if (sux->at(i) == res->as_Goto()->sux_at(0)) {
    -          assert(res->as_Goto()->is_safepoint() == sw.pair_at(i).offset() < 0, "safepoint state of Goto returned by canonicalizer incorrect");
    +          assert(res->as_Goto()->is_safepoint() == (sw.pair_at(i).offset() < 0), "safepoint state of Goto returned by canonicalizer incorrect");
             }
           }
         }
    @@ -2580,7 +2580,6 @@ void GraphBuilder::monitorenter(Value x, int bci) {
     
       // save state before locking in case of deoptimization after a NullPointerException
       ValueStack* state_before = copy_state_for_exception_with_bci(bci);
    -  compilation()->set_has_monitors(true);
       append_with_bci(new MonitorEnter(x, state()->lock(x), state_before, maybe_inlinetype), bci);
       kill_all();
     }
    @@ -3780,6 +3779,15 @@ int GraphBuilder::recursive_inline_level(ciMethod* cur_callee) const {
       return recur_level;
     }
     
    +static void set_flags_for_inlined_callee(Compilation* compilation, ciMethod* callee) {
    +  if (callee->has_reserved_stack_access()) {
    +    compilation->set_has_reserved_stack_access(true);
    +  }
    +  if (callee->is_synchronized() || callee->has_monitor_bytecodes()) {
    +    compilation->set_has_monitors(true);
    +  }
    +}
    +
     bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc, Value receiver) {
       const char* msg = nullptr;
     
    @@ -3796,9 +3804,7 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_r
       // method handle invokes
       if (callee->is_method_handle_intrinsic()) {
         if (try_method_handle_inline(callee, ignore_return)) {
    -      if (callee->has_reserved_stack_access()) {
    -        compilation()->set_has_reserved_stack_access(true);
    -      }
    +      set_flags_for_inlined_callee(compilation(), callee);
           return true;
         }
         return false;
    @@ -3809,9 +3815,7 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_r
           callee->check_intrinsic_candidate()) {
         if (try_inline_intrinsics(callee, ignore_return)) {
           print_inlining(callee, "intrinsic");
    -      if (callee->has_reserved_stack_access()) {
    -        compilation()->set_has_reserved_stack_access(true);
    -      }
    +      set_flags_for_inlined_callee(compilation(), callee);
           return true;
         }
         // try normal inlining
    @@ -3829,9 +3833,7 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_r
         bc = code();
       }
       if (try_inline_full(callee, holder_known, ignore_return, bc, receiver)) {
    -    if (callee->has_reserved_stack_access()) {
    -      compilation()->set_has_reserved_stack_access(true);
    -    }
    +    set_flags_for_inlined_callee(compilation(), callee);
         return true;
       }
     
    @@ -4738,7 +4740,9 @@ void GraphBuilder::append_unsafe_get_and_set(ciMethod* callee, bool is_add) {
     
     #ifndef PRODUCT
     void GraphBuilder::print_stats() {
    -  vmap()->print();
    +  if (UseLocalValueNumbering) {
    +    vmap()->print();
    +  }
     }
     #endif // PRODUCT
     
    diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp
    index 4430720a2f5..30e25f36479 100644
    --- a/src/hotspot/share/c1/c1_LinearScan.cpp
    +++ b/src/hotspot/share/c1/c1_LinearScan.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -4857,8 +4857,8 @@ void IntervalWalker::next_interval() {
         // intervals may start at same position -> prefer fixed interval
         kind = fixed != Interval::end() && fixed->from() <= any->from() ? fixedKind : anyKind;
     
    -    assert (kind == fixedKind && fixed->from() <= any->from() ||
    -            kind == anyKind   && any->from() <= fixed->from(), "wrong interval!!!");
    +    assert((kind == fixedKind && fixed->from() <= any->from()) ||
    +           (kind == anyKind   && any->from() <= fixed->from()), "wrong interval!!!");
         assert(any == Interval::end() || fixed == Interval::end() || any->from() != fixed->from() || kind == fixedKind, "if fixed and any-Interval start at same position, fixed must be processed first");
     
       } else if (fixed != Interval::end()) {
    diff --git a/src/hotspot/share/c1/c1_ValueStack.hpp b/src/hotspot/share/c1/c1_ValueStack.hpp
    index c120ca6b6e8..c89ddfda7ab 100644
    --- a/src/hotspot/share/c1/c1_ValueStack.hpp
    +++ b/src/hotspot/share/c1/c1_ValueStack.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -61,7 +61,7 @@ class ValueStack: public CompilationResourceObj {
       Values*  _locks;                               // the monitor stack (holding the locked values)
     
       Value check(ValueTag tag, Value t) {
    -    assert(tag == t->type()->tag() || tag == objectTag && t->type()->tag() == addressTag, "types must correspond");
    +    assert(tag == t->type()->tag() || (tag == objectTag && t->type()->tag() == addressTag), "types must correspond");
         return t;
       }
     
    diff --git a/src/hotspot/share/c1/c1_globals.hpp b/src/hotspot/share/c1/c1_globals.hpp
    index 08e9610b2a6..058091b3c43 100644
    --- a/src/hotspot/share/c1/c1_globals.hpp
    +++ b/src/hotspot/share/c1/c1_globals.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -275,9 +275,11 @@
       develop(bool, InstallMethods, true,                                       \
               "Install methods at the end of successful compilations")          \
                                                                                 \
    +  /* The compiler assumes, in many places, that methods are at most 1MB. */ \
    +  /* Therefore, we restrict this flag to at most 1MB.                    */ \
       develop(intx, NMethodSizeLimit, (64*K)*wordSize,                          \
               "Maximum size of a compiled method.")                             \
    -          range(0, max_jint)                                                \
    +          range(0, 1*M)                                                     \
                                                                                 \
       develop(bool, TraceFPUStack, false,                                       \
               "Trace emulation of the FPU stack (intel only)")                  \
    diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp
    index 9193c9f9d15..ba3883f3db5 100644
    --- a/src/hotspot/share/cds/cdsConfig.hpp
    +++ b/src/hotspot/share/cds/cdsConfig.hpp
    @@ -55,7 +55,7 @@ class CDSConfig : public AllStatic {
       static void initialize() NOT_CDS_RETURN;
       static void check_system_property(const char* key, const char* value) NOT_CDS_RETURN;
       static void check_unsupported_dumping_properties() NOT_CDS_RETURN;
    -  static bool check_vm_args_consistency(bool mode_flag_cmd_line) NOT_CDS_RETURN_(false);
    +  static bool check_vm_args_consistency(bool mode_flag_cmd_line) NOT_CDS_RETURN_(true);
     
       static bool module_patching_disables_cds() { return _module_patching_disables_cds; }
       static void set_module_patching_disables_cds() { _module_patching_disables_cds = true; }
    diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp
    index b687ad566b3..29e5af97c6a 100644
    --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp
    +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp
    @@ -92,11 +92,6 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
       //
       //       class                                         field                     type
       ADD_EXCL("java/lang/ClassLoader",                      "scl");                   // A
    -  ADD_EXCL("java/lang/invoke/InvokerBytecodeGenerator",  "DONTINLINE_SIG",         // B
    -                                                         "FORCEINLINE_SIG",        // B
    -                                                         "HIDDEN_SIG",             // B
    -                                                         "INJECTEDPROFILE_SIG",    // B
    -                                                         "LF_COMPILED_SIG");       // B
       ADD_EXCL("java/lang/Module",                           "ALL_UNNAMED_MODULE",     // A
                                                              "ALL_UNNAMED_MODULE_SET", // A
                                                              "EVERYONE_MODULE",        // A
    @@ -106,10 +101,6 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
       ADD_EXCL("java/lang/reflect/AccessFlag$Location",      "EMPTY_SET");             // E
     
       ADD_EXCL("java/lang/System",                           "bootLayer");             // A
    -  ADD_EXCL("java/lang/VersionProps",                     "VENDOR_URL_BUG",         // C
    -                                                         "VENDOR_URL_VM_BUG",      // C
    -                                                         "VENDOR_VERSION");        // C
    -  ADD_EXCL("java/net/URL$DefaultFactory",                "PREFIX");                // B FIXME: JDK-8276561
     
       // A dummy object used by HashSet. The value doesn't matter and it's never
       // tested for equality.
    @@ -118,7 +109,6 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
       ADD_EXCL("jdk/internal/loader/ClassLoaders",           "BOOT_LOADER",            // A
                                                              "APP_LOADER",             // A
                                                              "PLATFORM_LOADER");       // A
    -  ADD_EXCL("jdk/internal/loader/URLClassPath",           "JAVA_VERSION");          // B
       ADD_EXCL("jdk/internal/module/Builder",                "cachedVersion");         // D
       ADD_EXCL("jdk/internal/module/ModuleLoaderMap$Mapper", "APP_CLASSLOADER",        // A
                                                              "APP_LOADER_INDEX",       // A
    @@ -128,14 +118,10 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
     
       // This just points to an empty Map
       ADD_EXCL("jdk/internal/reflect/Reflection",            "methodFilterMap");       // E
    -  ADD_EXCL("jdk/internal/util/StaticProperty",           "FILE_ENCODING",          // C
    -                                                 "JAVA_LOCALE_USE_OLD_ISO_CODES"); // C
     
       // Integer for 0 and 1 are in java/lang/Integer$IntegerCache and are archived
       ADD_EXCL("sun/invoke/util/ValueConversions",           "ONE_INT",                // E
                                                              "ZERO_INT");              // E
    -  ADD_EXCL("sun/security/util/SecurityConstants",        "PROVIDER_VER");          // C
    -
     
     # undef ADD_EXCL
     
    @@ -229,6 +215,12 @@ inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo&
     
       StaticFieldInfo* info = _table.get(orig_obj);
       if (info != nullptr) {
    +    if (value.orig_referrer() == nullptr && java_lang_String::is_instance(orig_obj)) {
    +      // This string object is not referenced by any of the archived object graphs. It's archived
    +      // only because it's in the interned string table. So we are not in a condition that
    +      // should be flagged by CDSHeapVerifier.
    +      return true; /* keep on iterating */
    +    }
         ResourceMark rm;
         LogStream ls(Log(cds, heap)::warning());
         ls.print_cr("Archive heap points to a static field that may be reinitialized at runtime:");
    diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
    index fd073d49425..464b75ce1ba 100644
    --- a/src/hotspot/share/cds/filemap.cpp
    +++ b/src/hotspot/share/cds/filemap.cpp
    @@ -644,12 +644,14 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) {
       const char* file = ClassLoader::skip_uri_protocol(location->as_C_string());
       for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) {
         SharedClassPathEntry* ent = shared_path(i);
    -    assert(ent->in_named_module(), "must be");
    -    bool cond = strcmp(file, ent->name()) == 0;
    -    log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i,
    -                           location->as_C_string(), ent->name(), cond ? "same" : "different");
    -    if (cond) {
    -      return i;
    +    if (!ent->is_non_existent()) {
    +      assert(ent->in_named_module(), "must be");
    +      bool cond = strcmp(file, ent->name()) == 0;
    +      log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i,
    +                             location->as_C_string(), ent->name(), cond ? "same" : "different");
    +      if (cond) {
    +        return i;
    +      }
         }
       }
     
    @@ -1537,7 +1539,7 @@ BitMapView FileMapRegion::ptrmap_view() {
       return bitmap_view(false);
     }
     
    -bool FileMapRegion::check_region_crc() const {
    +bool FileMapRegion::check_region_crc(char* base) const {
       // This function should be called after the region has been properly
       // loaded into memory via FileMapInfo::map_region() or FileMapInfo::read_region().
       // I.e., this->mapped_base() must be valid.
    @@ -1546,8 +1548,8 @@ bool FileMapRegion::check_region_crc() const {
         return true;
       }
     
    -  assert(mapped_base() != nullptr, "must be initialized");
    -  int crc = ClassLoader::crc32(0, mapped_base(), (jint)sz);
    +  assert(base != nullptr, "must be initialized");
    +  int crc = ClassLoader::crc32(0, base, (jint)sz);
       if (crc != this->crc()) {
         log_warning(cds)("Checksum verification failed.");
         return false;
    @@ -1832,13 +1834,13 @@ bool FileMapInfo::read_region(int i, char* base, size_t size, bool do_commit) {
         return false;
       }
     
    -  r->set_mapped_from_file(false);
    -  r->set_mapped_base(base);
    -
    -  if (VerifySharedSpaces && !r->check_region_crc()) {
    +  if (VerifySharedSpaces && !r->check_region_crc(base)) {
         return false;
       }
     
    +  r->set_mapped_from_file(false);
    +  r->set_mapped_base(base);
    +
       return true;
     }
     
    @@ -1875,6 +1877,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba
           return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error.
         } else {
           assert(r->mapped_base() != nullptr, "must be initialized");
    +      return MAP_ARCHIVE_SUCCESS;
         }
       } else {
         // Note that this may either be a "fresh" mapping into unreserved address
    @@ -1889,15 +1892,16 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba
           _memory_mapping_failed = true;
           return MAP_ARCHIVE_MMAP_FAILURE;
         }
    +
    +    if (VerifySharedSpaces && !r->check_region_crc(requested_addr)) {
    +      return MAP_ARCHIVE_OTHER_FAILURE;
    +    }
    +
         r->set_mapped_from_file(true);
         r->set_mapped_base(requested_addr);
    -  }
     
    -  if (VerifySharedSpaces && !r->check_region_crc()) {
    -    return MAP_ARCHIVE_OTHER_FAILURE;
    +    return MAP_ARCHIVE_SUCCESS;
       }
    -
    -  return MAP_ARCHIVE_SUCCESS;
     }
     
     // The return value is the location of the archive relocation bitmap.
    @@ -1915,8 +1919,7 @@ char* FileMapInfo::map_bitmap_region() {
         return nullptr;
       }
     
    -  r->set_mapped_base(bitmap_base);
    -  if (VerifySharedSpaces && !r->check_region_crc()) {
    +  if (VerifySharedSpaces && !r->check_region_crc(bitmap_base)) {
         log_error(cds)("relocation bitmap CRC error");
         if (!os::unmap_memory(bitmap_base, r->used_aligned())) {
           fatal("os::unmap_memory of relocation bitmap failed");
    @@ -1925,6 +1928,7 @@ char* FileMapInfo::map_bitmap_region() {
       }
     
       r->set_mapped_from_file(true);
    +  r->set_mapped_base(bitmap_base);
       log_info(cds)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)",
                     is_static() ? "static " : "dynamic",
                     MetaspaceShared::bm, p2i(r->mapped_base()), p2i(r->mapped_end()),
    @@ -2200,13 +2204,14 @@ bool FileMapInfo::map_heap_region_impl() {
         return false;
       }
     
    -  r->set_mapped_base(base);
    -  if (VerifySharedSpaces && !r->check_region_crc()) {
    +  if (VerifySharedSpaces && !r->check_region_crc(base)) {
         dealloc_heap_region();
         log_info(cds)("UseSharedSpaces: mapped heap region is corrupt");
         return false;
       }
     
    +  r->set_mapped_base(base);
    +
       // If the requested range is different from the range allocated by GC, then
       // the pointers need to be patched.
       address mapped_start = (address) _mapped_heap_memregion.start();
    diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
    index 7ad1a2f4c34..150c4badc38 100644
    --- a/src/hotspot/share/cds/filemap.hpp
    +++ b/src/hotspot/share/cds/filemap.hpp
    @@ -90,6 +90,7 @@ class SharedClassPathEntry : public MetaspaceObj {
       bool is_dir()           const { return _type == dir_entry; }
       bool is_modules_image() const { return _type == modules_image_entry; }
       bool is_jar()           const { return _type == jar_entry; }
    +  bool is_non_existent()  const { return _type == non_existent_entry; }
       bool from_class_path_attr() { return _from_class_path_attr; }
       time_t timestamp() const { return _timestamp; }
       const char* name() const;
    @@ -171,7 +172,7 @@ class FileMapRegion: private CDSFileMapRegion {
       BitMapView ptrmap_view();
       bool has_ptrmap()                  { return _ptrmap_size_in_bits != 0; }
     
    -  bool check_region_crc() const;
    +  bool check_region_crc(char* base) const;
       void print(outputStream* st, int region_index);
     };
     
    diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp
    index 8aeecf1f57f..8a78a9dff70 100644
    --- a/src/hotspot/share/ci/ciEnv.hpp
    +++ b/src/hotspot/share/ci/ciEnv.hpp
    @@ -366,7 +366,7 @@ class ciEnv : StackObj {
     
       // The compiler task which has created this env.
       // May be useful to find out compile_id, comp_level, etc.
    -  CompileTask* task() { return _task; }
    +  CompileTask* task() const { return _task; }
     
       // Handy forwards to the task:
       int comp_level();   // task()->comp_level()
    @@ -448,7 +448,7 @@ class ciEnv : StackObj {
       static ciEnv* current(CompilerThread *thread) { return thread->env(); }
     
       // Per-compiler data.  (Used by C2 to publish the Compile* pointer.)
    -  void* compiler_data() { return _compiler_data; }
    +  void* compiler_data() const { return _compiler_data; }
       void set_compiler_data(void* x) { _compiler_data = x; }
     
       // Notice that a method has been inlined in the current compile;
    diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
    index 1e62d0aa0a2..7a022cdf181 100644
    --- a/src/hotspot/share/classfile/javaClasses.cpp
    +++ b/src/hotspot/share/classfile/javaClasses.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1367,7 +1367,7 @@ const char* java_lang_Class::as_external_name(oop java_class) {
     
     Klass* java_lang_Class::array_klass_acquire(oop java_class) {
       Klass* k = ((Klass*)java_class->metadata_field_acquire(_array_klass_offset));
    -  assert(k == nullptr || k->is_klass() && k->is_array_klass(), "should be array klass");
    +  assert(k == nullptr || (k->is_klass() && k->is_array_klass()), "should be array klass");
       return k;
     }
     
    diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp
    index 8178e3b3bb7..02723a42f42 100644
    --- a/src/hotspot/share/classfile/stringTable.hpp
    +++ b/src/hotspot/share/classfile/stringTable.hpp
    @@ -25,7 +25,7 @@
     #ifndef SHARE_CLASSFILE_STRINGTABLE_HPP
     #define SHARE_CLASSFILE_STRINGTABLE_HPP
     
    -#include "memory/allocation.hpp"
    +#include "memory/allStatic.hpp"
     #include "memory/padded.hpp"
     #include "oops/oop.hpp"
     #include "oops/oopHandle.hpp"
    @@ -37,15 +37,11 @@ class DumpedInternedStrings;
     class JavaThread;
     class SerializeClosure;
     
    -class StringTable;
     class StringTableConfig;
    -class StringTableCreateEntry;
     
    -class StringTable : public CHeapObj{
    +class StringTable : AllStatic {
       friend class VMStructs;
    -  friend class Symbol;
       friend class StringTableConfig;
    -  friend class StringTableCreateEntry;
     
       static volatile bool _has_work;
     
    diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp
    index b3ae4a37c92..1011e2595b1 100644
    --- a/src/hotspot/share/classfile/vmIntrinsics.hpp
    +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp
    @@ -600,6 +600,7 @@ class methodHandle;
       do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN)     \
       do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \
       do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_RN) \
    +  do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_RN) \
                                                                                                                             \
       /* support for UnsafeConstants */                                                                                     \
       do_class(jdk_internal_misc_UnsafeConstants,      "jdk/internal/misc/UnsafeConstants")                                 \
    diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp
    index 344c6775bc0..e8ee01f66c2 100644
    --- a/src/hotspot/share/classfile/vmSymbols.hpp
    +++ b/src/hotspot/share/classfile/vmSymbols.hpp
    @@ -424,6 +424,7 @@ class SerializeClosure;
       template(notifyJvmtiMount_name,                     "notifyJvmtiMount")                         \
       template(notifyJvmtiUnmount_name,                   "notifyJvmtiUnmount")                       \
       template(notifyJvmtiHideFrames_name,                "notifyJvmtiHideFrames")                    \
    +  template(notifyJvmtiDisableSuspend_name,            "notifyJvmtiDisableSuspend")                \
       template(doYield_name,                              "doYield")                                  \
       template(enter_name,                                "enter")                                    \
       template(enterSpecial_name,                         "enterSpecial")                             \
    diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp
    index 87d2344984b..46d77fee6b4 100644
    --- a/src/hotspot/share/code/codeBlob.cpp
    +++ b/src/hotspot/share/code/codeBlob.cpp
    @@ -164,7 +164,7 @@ RuntimeBlob::RuntimeBlob(
     void RuntimeBlob::free(RuntimeBlob* blob) {
       assert(blob != nullptr, "caller must check for nullptr");
       ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock
    -  blob->purge();
    +  blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
       {
         MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
         CodeCache::free(blob);
    @@ -173,7 +173,7 @@ void RuntimeBlob::free(RuntimeBlob* blob) {
       MemoryService::track_code_cache_memory_usage();
     }
     
    -void CodeBlob::purge(bool free_code_cache_data) {
    +void CodeBlob::purge(bool free_code_cache_data, bool unregister_nmethod) {
       if (_oop_maps != nullptr) {
         delete _oop_maps;
         _oop_maps = nullptr;
    diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp
    index 5945ff998cd..a91ec482f02 100644
    --- a/src/hotspot/share/code/codeBlob.hpp
    +++ b/src/hotspot/share/code/codeBlob.hpp
    @@ -143,7 +143,7 @@ class CodeBlob {
       static unsigned int align_code_offset(int offset);
     
       // Deletion
    -  virtual void purge(bool free_code_cache_data = true);
    +  virtual void purge(bool free_code_cache_data, bool unregister_nmethod);
     
       // Typing
       virtual bool is_buffer_blob() const                 { return false; }
    diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp
    index 9b10dab2ef7..bf8c1d84e71 100644
    --- a/src/hotspot/share/code/codeCache.cpp
    +++ b/src/hotspot/share/code/codeCache.cpp
    @@ -355,16 +355,8 @@ void CodeCache::initialize_heaps() {
     }
     
     size_t CodeCache::page_size(bool aligned, size_t min_pages) {
    -  if (os::can_execute_large_page_memory()) {
    -    if (InitialCodeCacheSize < ReservedCodeCacheSize) {
    -      // Make sure that the page size allows for an incremental commit of the reserved space
    -      min_pages = MAX2(min_pages, (size_t)8);
    -    }
    -    return aligned ? os::page_size_for_region_aligned(ReservedCodeCacheSize, min_pages) :
    -                     os::page_size_for_region_unaligned(ReservedCodeCacheSize, min_pages);
    -  } else {
    -    return os::vm_page_size();
    -  }
    +  return aligned ? os::page_size_for_region_aligned(ReservedCodeCacheSize, min_pages) :
    +                   os::page_size_for_region_unaligned(ReservedCodeCacheSize, min_pages);
     }
     
     ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size, size_t rs_ps) {
    @@ -1171,7 +1163,11 @@ void CodeCache::initialize() {
         FLAG_SET_ERGO(NonNMethodCodeHeapSize, (uintx)os::vm_page_size());
         FLAG_SET_ERGO(ProfiledCodeHeapSize, 0);
         FLAG_SET_ERGO(NonProfiledCodeHeapSize, 0);
    -    ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize, page_size(false, 8));
    +
    +    // If InitialCodeCacheSize is equal to ReservedCodeCacheSize, then it's more likely
    +    // users want to use the largest available page.
    +    const size_t min_pages = (InitialCodeCacheSize == ReservedCodeCacheSize) ? 1 : 8;
    +    ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize, page_size(false, min_pages));
         // Register CodeHeaps with LSan as we sometimes embed pointers to malloc memory.
         LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size());
         add_heap(rs, "CodeCache", CodeBlobType::All);
    @@ -1819,16 +1815,20 @@ void CodeCache::log_state(outputStream* st) {
     }
     
     #ifdef LINUX
    -void CodeCache::write_perf_map() {
    +void CodeCache::write_perf_map(const char* filename) {
       MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     
    -  // Perf expects to find the map file at /tmp/perf-.map.
    +  // Perf expects to find the map file at /tmp/perf-.map
    +  // if the file name is not specified.
       char fname[32];
    -  jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id());
    +  if (filename == nullptr) {
    +    jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id());
    +    filename = fname;
    +  }
     
    -  fileStream fs(fname, "w");
    +  fileStream fs(filename, "w");
       if (!fs.is_open()) {
    -    log_warning(codecache)("Failed to create %s for perf map", fname);
    +    log_warning(codecache)("Failed to create %s for perf map", filename);
         return;
       }
     
    diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp
    index 5418a29e58f..103268c8ffc 100644
    --- a/src/hotspot/share/code/codeCache.hpp
    +++ b/src/hotspot/share/code/codeCache.hpp
    @@ -227,7 +227,7 @@ class CodeCache : AllStatic {
       static void print_trace(const char* event, CodeBlob* cb, uint size = 0) PRODUCT_RETURN;
       static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
       static void log_state(outputStream* st);
    -  LINUX_ONLY(static void write_perf_map();)
    +  LINUX_ONLY(static void write_perf_map(const char* filename = nullptr);)
       static const char* get_code_heap_name(CodeBlobType code_blob_type)  { return (heap_available(code_blob_type) ? get_code_heap(code_blob_type)->name() : "Unused"); }
       static void report_codemem_full(CodeBlobType code_blob_type, bool print);
     
    diff --git a/src/hotspot/share/code/codeCache.inline.hpp b/src/hotspot/share/code/codeCache.inline.hpp
    index bea66cf0010..5ab7187cd26 100644
    --- a/src/hotspot/share/code/codeCache.inline.hpp
    +++ b/src/hotspot/share/code/codeCache.inline.hpp
    @@ -37,10 +37,9 @@ inline CodeBlob* CodeCache::find_blob_fast(void* pc) {
     inline CodeBlob* CodeCache::find_blob_and_oopmap(void* pc, int& slot) {
       NativePostCallNop* nop = nativePostCallNop_at((address) pc);
       CodeBlob* cb;
    -  if (nop != nullptr && nop->displacement() != 0) {
    -    int offset = (nop->displacement() & 0xffffff);
    +  int offset;
    +  if (nop != nullptr && nop->decode(slot, offset)) {
         cb = (CodeBlob*) ((address) pc - offset);
    -    slot = ((nop->displacement() >> 24) & 0xff);
         assert(cb == CodeCache::find_blob(pc), "must be");
       } else {
         cb = CodeCache::find_blob(pc);
    @@ -52,9 +51,12 @@ inline CodeBlob* CodeCache::find_blob_and_oopmap(void* pc, int& slot) {
     
     inline int CodeCache::find_oopmap_slot_fast(void* pc) {
       NativePostCallNop* nop = nativePostCallNop_at((address) pc);
    -  return (nop != nullptr && nop->displacement() != 0)
    -      ? ((nop->displacement() >> 24) & 0xff)
    -      : -1;
    +  int oopmap_slot;
    +  int cb_offset;
    +  if (nop != nullptr && nop->decode(oopmap_slot, cb_offset)) {
    +    return oopmap_slot;
    +  }
    +  return -1;
     }
     
     #endif // SHARE_VM_COMPILER_CODECACHE_INLINE_HPP
    diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp
    index 42cfd94f13c..74e70230f3a 100644
    --- a/src/hotspot/share/code/compiledIC.cpp
    +++ b/src/hotspot/share/code/compiledIC.cpp
    @@ -128,11 +128,13 @@ void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub
         tty->cr();
       }
     
    +#ifdef ASSERT
       {
         CodeBlob* cb = CodeCache::find_blob(_call->instruction_address());
         assert(cb != nullptr && cb->is_compiled(), "must be compiled");
    -    _call->set_destination_mt_safe(entry_point);
       }
    +#endif
    +  _call->set_destination_mt_safe(entry_point);
     
       if (is_optimized() || is_icstub) {
         // Optimized call sites don't have a cache value and ICStub call
    @@ -291,10 +293,10 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod
         }
       }
     
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
         assert(call_info->selected_method() != nullptr, "Unexpected null selected method");
    -    tty->print_cr ("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT,
    +    log_trace(inlinecache)("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT,
                        p2i(instruction_address()), call_info->selected_method()->print_value_string(), p2i(entry));
       }
     
    @@ -364,10 +366,11 @@ bool CompiledIC::is_call_to_interpreted() const {
     
     bool CompiledIC::set_to_clean(bool in_use) {
       assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
    -  if (TraceInlineCacheClearing || TraceICs) {
    +  if (TraceInlineCacheClearing) {
         tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address()));
         print();
       }
    +  log_trace(inlinecache)("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address()));
     
       address entry = _call->get_resolve_call_stub(is_optimized());
     
    @@ -433,9 +436,9 @@ bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
           methodHandle method (thread, (Method*)info.cached_metadata());
           _call->set_to_interpreted(method, info);
     
    -      if (TraceICs) {
    -         ResourceMark rm(thread);
    -         tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to interpreter: %s",
    +      {
    +        ResourceMark rm(thread);
    +        log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to interpreter: %s",
                p2i(instruction_address()),
                method->print_value_string());
           }
    @@ -449,9 +452,9 @@ bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
           // LSan appears unable to follow malloc-based memory consistently when embedded as an
           // immediate in generated machine code. So we have to ignore it.
           LSAN_IGNORE_OBJECT(holder);
    -      if (TraceICs) {
    +      {
              ResourceMark rm(thread);
    -         tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to interpreter via icholder ", p2i(instruction_address()));
    +         log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to interpreter via icholder ", p2i(instruction_address()));
           }
         }
       } else {
    @@ -479,10 +482,10 @@ bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
           }
         }
     
    -    if (TraceICs) {
    +    {
           ResourceMark rm(thread);
           assert(info.cached_metadata() == nullptr || info.cached_metadata()->is_klass(), "must be");
    -      tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to compiled (rcvr klass = %s) %s",
    +      log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to compiled (rcvr klass = %s) %s",
             p2i(instruction_address()),
             (info.cached_metadata() != nullptr) ? ((Klass*)info.cached_metadata())->print_value_string() : "nullptr",
             (safe) ? "" : " via stub");
    @@ -609,9 +612,9 @@ bool CompiledDirectStaticCall::is_call_to_interpreted() const {
     }
     
     void CompiledStaticCall::set_to_compiled(address entry) {
    -  if (TraceICs) {
    +  {
         ResourceMark rm;
    -    tty->print_cr("%s@" INTPTR_FORMAT ": set_to_compiled " INTPTR_FORMAT,
    +    log_trace(inlinecache)("%s@" INTPTR_FORMAT ": set_to_compiled " INTPTR_FORMAT,
             name(),
             p2i(instruction_address()),
             p2i(entry));
    diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp
    index a7b1b028c34..dda796dfad9 100644
    --- a/src/hotspot/share/code/compiledMethod.hpp
    +++ b/src/hotspot/share/code/compiledMethod.hpp
    @@ -174,7 +174,7 @@ class CompiledMethod : public CodeBlob {
     
       void* _gc_data;
     
    -  virtual void purge(bool free_code_cache_data = true) = 0;
    +  virtual void purge(bool free_code_cache_data, bool unregister_nmethod) = 0;
     
     private:
       DeoptimizationStatus deoptimization_status() const {
    diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
    index 23095b507d9..0784699c64e 100644
    --- a/src/hotspot/share/code/nmethod.cpp
    +++ b/src/hotspot/share/code/nmethod.cpp
    @@ -1146,10 +1146,7 @@ static void install_post_call_nop_displacement(nmethod* nm, address pc) {
       int oopmap_slot = nm->oop_maps()->find_slot_for_offset(int((intptr_t) pc - (intptr_t) nm->code_begin()));
       if (oopmap_slot < 0) { // this can happen at asynchronous (non-safepoint) stackwalks
         log_debug(codecache)("failed to find oopmap for cb: " INTPTR_FORMAT " offset: %d", cbaddr, (int) offset);
    -  } else if (((oopmap_slot & 0xff) == oopmap_slot) && ((offset & 0xffffff) == offset)) {
    -    jint value = (oopmap_slot << 24) | (jint) offset;
    -    nop->patch(value);
    -  } else {
    +  } else if (!nop->patch(oopmap_slot, offset)) {
         log_debug(codecache)("failed to encode %d %d", oopmap_slot, (int) offset);
       }
     }
    @@ -1453,7 +1450,9 @@ void nmethod::unlink() {
       ClassUnloadingContext::context()->register_unlinked_nmethod(this);
     }
     
    -void nmethod::purge(bool free_code_cache_data) {
    +void nmethod::purge(bool free_code_cache_data, bool unregister_nmethod) {
    +  assert(!free_code_cache_data, "must only call not freeing code cache data");
    +
       MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     
       // completely deallocate this method
    @@ -1473,13 +1472,13 @@ void nmethod::purge(bool free_code_cache_data) {
         ec = next;
       }
     
    -  Universe::heap()->unregister_nmethod(this);
    +  if (unregister_nmethod) {
    +    Universe::heap()->unregister_nmethod(this);
    +  }
    +
       CodeCache::unregister_old_nmethod(this);
     
    -  CodeBlob::purge();
    -  if (free_code_cache_data) {
    -    CodeCache::free(this);
    -  }
    +  CodeBlob::purge(free_code_cache_data, unregister_nmethod);
     }
     
     oop nmethod::oop_at(int index) const {
    diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp
    index a8c92d7e290..5e27ee665fa 100644
    --- a/src/hotspot/share/code/nmethod.hpp
    +++ b/src/hotspot/share/code/nmethod.hpp
    @@ -529,7 +529,7 @@ class nmethod : public CompiledMethod {
       void unlink();
     
       // Deallocate this nmethod - called by the GC
    -  void purge(bool free_code_cache_data = true);
    +  void purge(bool free_code_cache_data, bool unregister_nmethod);
     
       // See comment at definition of _last_seen_on_stack
       void mark_as_maybe_on_stack();
    diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp
    index d2e70fbd6db..bfb3db72d72 100644
    --- a/src/hotspot/share/code/relocInfo.cpp
    +++ b/src/hotspot/share/code/relocInfo.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -150,8 +150,8 @@ void RelocIterator::initialize(CompiledMethod* nm, address begin, address limit)
     
     RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) {
       initialize_misc();
    -  assert((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr) ||
    -         (cs->locs_start() == nullptr) && (cs->locs_end() == nullptr), "valid start and end pointer");
    +  assert(((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr)) ||
    +         ((cs->locs_start() == nullptr) && (cs->locs_end() == nullptr)), "valid start and end pointer");
       _current = cs->locs_start()-1;
       _end     = cs->locs_end();
       _addr    = cs->start();
    diff --git a/src/hotspot/share/compiler/compilationFailureInfo.cpp b/src/hotspot/share/compiler/compilationFailureInfo.cpp
    new file mode 100644
    index 00000000000..e3f3353589e
    --- /dev/null
    +++ b/src/hotspot/share/compiler/compilationFailureInfo.cpp
    @@ -0,0 +1,121 @@
    +/*
    + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023, Red Hat, Inc. 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
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +#include "precompiled.hpp"
    +
    +#if defined(COMPILER1) || defined(COMPILER2)
    +
    +#ifdef COMPILER1
    +#include "c1/c1_Compilation.hpp"
    +#endif
    +#include "ci/ciEnv.hpp"
    +#include "compiler/abstractCompiler.hpp"
    +#include "compiler/compilationFailureInfo.hpp"
    +#include "compiler/compileTask.hpp"
    +#ifdef COMPILER2
    +#include "opto/node.hpp"
    +#include "opto/compile.hpp"
    +#endif
    +#include "runtime/os.hpp"
    +#include "utilities/ostream.hpp"
    +#include "utilities/nativeCallStack.hpp"
    +
    +CompilationFailureInfo::CompilationFailureInfo(const char* failure_reason) :
    +  _stack(2),
    +  _failure_reason(os::strdup(failure_reason)),
    +  _elapsed_seconds(os::elapsedTime()),
    +  _compile_id(ciEnv::current()->task()->compile_id())
    +{}
    +
    +CompilationFailureInfo::~CompilationFailureInfo() {
    +  os::free(_failure_reason);
    +}
    +
    +void CompilationFailureInfo::print_on(outputStream* st) const {
    +  st->print("  Time: ");
    +  os::print_elapsed_time(st, _elapsed_seconds);
    +  st->print_cr("  Compile id: %d", _compile_id);
    +  st->print_cr("  Reason: '%s'", _failure_reason);
    +  st->print_cr("  Callstack: ");
    +  _stack.print_on(st);
    +  st->cr();
    +}
    +
    +// Convenience function to print current compile failure iff
    +// current thread is compiler thread and there is a pending failure.
    +// Otherwise prints nothing.
    +bool CompilationFailureInfo::print_pending_compilation_failure(outputStream* st) {
    +
    +  const CompilationFailureInfo* info = nullptr;
    +
    +  // Carefully tiptoeing because we are called from the error reporter and
    +  // nothing is certain.
    +
    +  const Thread* const t = Thread::current();
    +  if (t == nullptr || !t->is_Compiler_thread()) {
    +    return false;
    +  }
    +
    +  const ciEnv* const env = ciEnv::current();
    +  if (env == nullptr) {
    +    return false;
    +  }
    +
    +  const CompileTask* const task = env->task();
    +  if (task == nullptr) {
    +    return false;
    +  }
    +
    +  const AbstractCompiler* const compiler = task->compiler();
    +  if (compiler == nullptr) {
    +    return false;
    +  }
    +
    +#ifdef COMPILER1
    +  if (compiler->type() == compiler_c1) {
    +    const Compilation* const C = (Compilation*)env->compiler_data();
    +    if (C != nullptr) {
    +      info = C->first_failure_details();
    +    }
    +  }
    +#endif
    +#ifdef COMPILER2
    +  if (compiler->type() == compiler_c2) {
    +    const Compile* const C = (Compile*)env->compiler_data();
    +    if (C != nullptr) {
    +      info = C->first_failure_details();
    +    }
    +  }
    +#endif
    +
    +  if (info != nullptr) {
    +    st->print_cr("Pending compilation failure details for thread " PTR_FORMAT ":", p2i(t));
    +    info->print_on(st);
    +  }
    +
    +  return true;
    +}
    +
    +#endif // defined(COMPILER1) || defined(COMPILER2)
    diff --git a/src/hotspot/share/compiler/compilationFailureInfo.hpp b/src/hotspot/share/compiler/compilationFailureInfo.hpp
    new file mode 100644
    index 00000000000..3de62eb69da
    --- /dev/null
    +++ b/src/hotspot/share/compiler/compilationFailureInfo.hpp
    @@ -0,0 +1,57 @@
    +/*
    + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023, Red Hat, Inc. 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
    + * 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_COMPILER_COMPILATIONFAILUREINFO_HPP
    +#define SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP
    +
    +#if defined(COMPILER1) || defined(COMPILER2)
    +
    +#include "memory/allocation.hpp"
    +#include "utilities/globalDefinitions.hpp"
    +#include "utilities/nativeCallStack.hpp"
    +
    +class outputStream;
    +class Symbol;
    +
    +class CompilationFailureInfo : public CHeapObj {
    +  NativeCallStack _stack;
    +  char* const _failure_reason;
    +  const double _elapsed_seconds;
    +  const int _compile_id;
    +public:
    +  CompilationFailureInfo(const char* failure_reason);
    +  ~CompilationFailureInfo();
    +  void print_on(outputStream* st) const;
    +
    +  // Convenience function to print, safely, current compile failure iff
    +  // current thread is compiler thread and there is an ongoing compilation
    +  // and a pending failure.
    +  // Otherwise prints nothing.
    +  static bool print_pending_compilation_failure(outputStream* st);
    +};
    +
    +#endif // defined(COMPILER1) || defined(COMPILER2)
    +
    +#endif // SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP
    diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
    index 39e45ec199a..6e992299744 100644
    --- a/src/hotspot/share/compiler/compileBroker.cpp
    +++ b/src/hotspot/share/compiler/compileBroker.cpp
    @@ -1788,7 +1788,7 @@ bool CompileBroker::init_compiler_runtime() {
     void CompileBroker::free_buffer_blob_if_allocated(CompilerThread* thread) {
       BufferBlob* blob = thread->get_buffer_blob();
       if (blob != nullptr) {
    -    blob->purge();
    +    blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
         MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
         CodeCache::free(blob);
       }
    diff --git a/src/hotspot/share/compiler/compilerDefinitions.inline.hpp b/src/hotspot/share/compiler/compilerDefinitions.inline.hpp
    index ed456a42157..d490387672d 100644
    --- a/src/hotspot/share/compiler/compilerDefinitions.inline.hpp
    +++ b/src/hotspot/share/compiler/compilerDefinitions.inline.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -57,7 +57,7 @@ inline bool CompilerConfig::is_c1_only() {
     }
     
     inline bool CompilerConfig::is_c1_or_interpreter_only_no_jvmci() {
    -  assert(is_jvmci_compiler() && is_jvmci() || !is_jvmci_compiler(), "JVMCI compiler implies enabled JVMCI");
    +  assert(!is_jvmci_compiler() || is_jvmci(), "JVMCI compiler implies enabled JVMCI");
       return !is_jvmci() && (is_interpreter_only() || is_c1_only());
     }
     
    @@ -114,7 +114,7 @@ inline bool CompilerConfig::is_c2_or_jvmci_compiler_only() {
     
     // Tiered is basically C1 & (C2 | JVMCI) minus all the odd cases with restrictions.
     inline bool CompilerConfig::is_tiered() {
    -  assert(is_c1_simple_only() && is_c1_only() || !is_c1_simple_only(), "c1 simple mode must imply c1-only mode");
    +  assert(!is_c1_simple_only() || is_c1_only(), "c1 simple mode must imply c1-only mode");
       return has_tiered() && !is_interpreter_only() && !is_c1_only() && !is_c2_or_jvmci_compiler_only();
     }
     
    diff --git a/src/hotspot/share/compiler/compiler_globals.hpp b/src/hotspot/share/compiler/compiler_globals.hpp
    index 7f1f08b68ef..71b475392cf 100644
    --- a/src/hotspot/share/compiler/compiler_globals.hpp
    +++ b/src/hotspot/share/compiler/compiler_globals.hpp
    @@ -379,6 +379,10 @@
               "Don't compile methods larger than this if "                      \
               "+DontCompileHugeMethods")                                        \
                                                                                 \
    +  product(bool, CaptureBailoutInformation, trueInDebug, DIAGNOSTIC,         \
    +          "If compilation is stopped with an error, capture diagnostic "    \
    +          "information at the bailout point")                               \
    +                                                                            \
     
     // end of COMPILER_FLAGS
     
    diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp
    index b8a7c677f7f..79b50cd0ea9 100644
    --- a/src/hotspot/share/gc/g1/g1Arguments.cpp
    +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp
    @@ -126,7 +126,6 @@ void G1Arguments::initialize_mark_stack_size() {
         FLAG_SET_ERGO(MarkStackSize, mark_stack_size);
       }
     
    -  log_trace(gc)("MarkStackSize: %uk  MarkStackSizeMax: %uk", (uint)(MarkStackSize / K), (uint)(MarkStackSizeMax / K));
     }
     
     
    diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp
    index 59d877554ea..3b933dfa7f9 100644
    --- a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp
    @@ -187,6 +187,15 @@ class G1CodeRootSetHashTable : public CHeapObj {
         }
       }
     
    +  // Removes dead/unlinked entries.
    +  void bulk_remove() {
    +    auto delete_check = [&] (nmethod** value) {
    +      return (*value)->is_unlinked();
    +    };
    +
    +    clean(delete_check);
    +  }
    +
       // Calculate the log2 of the table size we want to shrink to.
       size_t log2_target_shrink_size(size_t current_size) const {
         // A table with the new size should be at most filled by this factor. Otherwise
    @@ -255,6 +264,11 @@ bool G1CodeRootSet::remove(nmethod* method) {
       return _table->remove(method);
     }
     
    +void G1CodeRootSet::bulk_remove() {
    +  assert(!_is_iterating, "should not mutate while iterating the table");
    +  _table->bulk_remove();
    +}
    +
     bool G1CodeRootSet::contains(nmethod* method) {
       return _table->contains(method);
     }
    diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp
    index d1051e6e42e..9c5ccdd1202 100644
    --- a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp
    +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp
    @@ -44,6 +44,7 @@ class G1CodeRootSet {
     
       void add(nmethod* method);
       bool remove(nmethod* method);
    +  void bulk_remove();
       bool contains(nmethod* method);
       void clear();
     
    diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    index 25d7ed13ab0..7a630c27f79 100644
    --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    @@ -2517,6 +2517,7 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
       GCTraceTime(Debug, gc, phases) debug(description, timer);
     
       ClassUnloadingContext ctx(workers()->active_workers(),
    +                            false /* unregister_nmethods_during_purge */,
                                 false /* lock_codeblob_free_separately */);
       {
         CodeCache::UnlinkingScope scope(is_alive);
    @@ -2528,6 +2529,10 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
         GCTraceTime(Debug, gc, phases) t("Purge Unlinked NMethods", timer);
         ctx.purge_nmethods();
       }
    +  {
    +    GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", timer);
    +    G1CollectedHeap::heap()->bulk_unregister_nmethods();
    +  }
       {
         GCTraceTime(Debug, gc, phases) t("Free Code Blobs", timer);
         ctx.free_code_blobs();
    @@ -2539,6 +2544,33 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
       }
     }
     
    +class G1BulkUnregisterNMethodTask : public WorkerTask {
    +  HeapRegionClaimer _hrclaimer;
    +
    +  class UnregisterNMethodsHeapRegionClosure : public HeapRegionClosure {
    +  public:
    +
    +    bool do_heap_region(HeapRegion* hr) {
    +      hr->rem_set()->bulk_remove_code_roots();
    +      return false;
    +    }
    +  } _cl;
    +
    +public:
    +  G1BulkUnregisterNMethodTask(uint num_workers)
    +  : WorkerTask("G1 Remove Unlinked NMethods From Code Root Set Task"),
    +    _hrclaimer(num_workers) { }
    +
    +  void work(uint worker_id) {
    +    G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&_cl, &_hrclaimer, worker_id);
    +  }
    +};
    +
    +void G1CollectedHeap::bulk_unregister_nmethods() {
    +  uint num_workers = workers()->active_workers();
    +  G1BulkUnregisterNMethodTask t(num_workers);
    +  workers()->run_task(&t);
    +}
     
     bool G1STWSubjectToDiscoveryClosure::do_object_b(oop obj) {
       assert(obj != nullptr, "must not be null");
    @@ -2963,31 +2995,6 @@ class RegisterNMethodOopClosure: public OopClosure {
       void do_oop(narrowOop* p) { ShouldNotReachHere(); }
     };
     
    -class UnregisterNMethodOopClosure: public OopClosure {
    -  G1CollectedHeap* _g1h;
    -  nmethod* _nm;
    -
    -public:
    -  UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
    -    _g1h(g1h), _nm(nm) {}
    -
    -  void do_oop(oop* p) {
    -    oop heap_oop = RawAccess<>::oop_load(p);
    -    if (!CompressedOops::is_null(heap_oop)) {
    -      oop obj = CompressedOops::decode_not_null(heap_oop);
    -      HeapRegion* hr = _g1h->heap_region_containing(obj);
    -      assert(!hr->is_continues_humongous(),
    -             "trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT
    -             " starting at " HR_FORMAT,
    -             p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()));
    -
    -      hr->remove_code_root(_nm);
    -    }
    -  }
    -
    -  void do_oop(narrowOop* p) { ShouldNotReachHere(); }
    -};
    -
     void G1CollectedHeap::register_nmethod(nmethod* nm) {
       guarantee(nm != nullptr, "sanity");
       RegisterNMethodOopClosure reg_cl(this, nm);
    @@ -2995,9 +3002,8 @@ void G1CollectedHeap::register_nmethod(nmethod* nm) {
     }
     
     void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
    -  guarantee(nm != nullptr, "sanity");
    -  UnregisterNMethodOopClosure reg_cl(this, nm);
    -  nm->oops_do(®_cl, true);
    +  // We always unregister nmethods in bulk during code unloading only.
    +  ShouldNotReachHere();
     }
     
     void G1CollectedHeap::update_used_after_gc(bool evacuation_failed) {
    diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
    index 1d25ea278de..58ac36a734f 100644
    --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
    +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
    @@ -1270,6 +1270,8 @@ class G1CollectedHeap : public CollectedHeap {
     
       void unload_classes_and_code(const char* description, BoolObjectClosure* cl, GCTimer* timer);
     
    +  void bulk_unregister_nmethods();
    +
       // Verification
     
       // Perform any cleanup actions necessary before allowing a verification.
    diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
    index 78e1bec3438..533817f9724 100644
    --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
    +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
    @@ -75,6 +75,7 @@
     #include "utilities/align.hpp"
     #include "utilities/formatBuffer.hpp"
     #include "utilities/growableArray.hpp"
    +#include "utilities/powerOfTwo.hpp"
     
     bool G1CMBitMapClosure::do_addr(HeapWord* const addr) {
       assert(addr < _cm->finger(), "invariant");
    @@ -94,80 +95,173 @@ bool G1CMBitMapClosure::do_addr(HeapWord* const addr) {
     }
     
     G1CMMarkStack::G1CMMarkStack() :
    -  _max_chunk_capacity(0),
    -  _base(nullptr),
    -  _chunk_capacity(0) {
    +  _chunk_allocator() {
       set_empty();
     }
     
    -bool G1CMMarkStack::resize(size_t new_capacity) {
    -  assert(is_empty(), "Only resize when stack is empty.");
    -  assert(new_capacity <= _max_chunk_capacity,
    -         "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity);
    +size_t G1CMMarkStack::capacity_alignment() {
    +  return (size_t)lcm(os::vm_allocation_granularity(), sizeof(TaskQueueEntryChunk)) / sizeof(G1TaskQueueEntry);
    +}
     
    -  TaskQueueEntryChunk* new_base = MmapArrayAllocator::allocate_or_null(new_capacity, mtGC);
    +bool G1CMMarkStack::initialize() {
    +  guarantee(_chunk_allocator.capacity() == 0, "G1CMMarkStack already initialized.");
     
    -  if (new_base == nullptr) {
    -    log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(TaskQueueEntryChunk));
    -    return false;
    +  size_t initial_capacity = MarkStackSize;
    +  size_t max_capacity = MarkStackSizeMax;
    +
    +  size_t const TaskEntryChunkSizeInVoidStar = sizeof(TaskQueueEntryChunk) / sizeof(G1TaskQueueEntry);
    +
    +  size_t max_num_chunks = align_up(max_capacity, capacity_alignment()) / TaskEntryChunkSizeInVoidStar;
    +  size_t initial_num_chunks = align_up(initial_capacity, capacity_alignment()) / TaskEntryChunkSizeInVoidStar;
    +
    +  initial_num_chunks = round_up_power_of_2(initial_num_chunks);
    +  max_num_chunks = MAX2(initial_num_chunks, max_num_chunks);
    +
    +  size_t limit = (INT_MAX - 1);
    +  max_capacity = MIN2((max_num_chunks * TaskEntryChunkSizeInVoidStar), limit);
    +  initial_capacity = MIN2((initial_num_chunks * TaskEntryChunkSizeInVoidStar), limit);
    +
    +  FLAG_SET_ERGO(MarkStackSizeMax, max_capacity);
    +  FLAG_SET_ERGO(MarkStackSize, initial_capacity);
    +
    +  log_trace(gc)("MarkStackSize: %uk  MarkStackSizeMax: %uk", (uint)(MarkStackSize / K), (uint)(MarkStackSizeMax / K));
    +
    +  log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT,
    +                initial_num_chunks, max_capacity);
    +
    +  return _chunk_allocator.initialize(initial_num_chunks, max_num_chunks);
    +}
    +
    +G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::ChunkAllocator::allocate_new_chunk() {
    +  if (_size >= _max_capacity) {
    +    return nullptr;
       }
    -  // Release old mapping.
    -  if (_base != nullptr) {
    -    MmapArrayAllocator::free(_base, _chunk_capacity);
    +
    +  size_t cur_idx = Atomic::fetch_then_add(&_size, 1u);
    +
    +  if (cur_idx >= _max_capacity) {
    +    return nullptr;
       }
     
    -  _base = new_base;
    -  _chunk_capacity = new_capacity;
    -  set_empty();
    +  size_t bucket = get_bucket(cur_idx);
    +  if (Atomic::load_acquire(&_buckets[bucket]) == nullptr) {
    +    if (!_should_grow) {
    +      // Prefer to restart the CM.
    +      return nullptr;
    +    }
     
    -  return true;
    -}
    +    MutexLocker x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
    +    if (Atomic::load_acquire(&_buckets[bucket]) == nullptr) {
    +      if (!expand()) {
    +        return nullptr;
    +      }
    +    }
    +  }
     
    -size_t G1CMMarkStack::capacity_alignment() {
    -  return (size_t)lcm(os::vm_allocation_granularity(), sizeof(TaskQueueEntryChunk)) / sizeof(G1TaskQueueEntry);
    +  size_t bucket_idx = get_bucket_index(cur_idx);
    +  TaskQueueEntryChunk* result = ::new (&_buckets[bucket][bucket_idx]) TaskQueueEntryChunk;
    +  result->next = nullptr;
    +  return result;
     }
     
    -bool G1CMMarkStack::initialize(size_t initial_capacity, size_t max_capacity) {
    -  guarantee(_max_chunk_capacity == 0, "G1CMMarkStack already initialized.");
    +G1CMMarkStack::ChunkAllocator::ChunkAllocator() :
    +  _min_capacity(0),
    +  _max_capacity(0),
    +  _capacity(0),
    +  _num_buckets(0),
    +  _should_grow(false),
    +  _buckets(nullptr),
    +  _size(0)
    +{ }
     
    -  size_t const TaskEntryChunkSizeInVoidStar = sizeof(TaskQueueEntryChunk) / sizeof(G1TaskQueueEntry);
    +bool G1CMMarkStack::ChunkAllocator::initialize(size_t initial_capacity, size_t max_capacity) {
    +  guarantee(is_power_of_2(initial_capacity), "Invalid initial_capacity");
     
    -  _max_chunk_capacity = align_up(max_capacity, capacity_alignment()) / TaskEntryChunkSizeInVoidStar;
    -  size_t initial_chunk_capacity = align_up(initial_capacity, capacity_alignment()) / TaskEntryChunkSizeInVoidStar;
    +  _min_capacity = initial_capacity;
    +  _max_capacity = max_capacity;
    +  _num_buckets  = get_bucket(_max_capacity) + 1;
     
    -  guarantee(initial_chunk_capacity <= _max_chunk_capacity,
    -            "Maximum chunk capacity " SIZE_FORMAT " smaller than initial capacity " SIZE_FORMAT,
    -            _max_chunk_capacity,
    -            initial_chunk_capacity);
    +  _buckets = NEW_C_HEAP_ARRAY(TaskQueueEntryChunk*, _num_buckets, mtGC);
     
    -  log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT,
    -                initial_chunk_capacity, _max_chunk_capacity);
    +  for (size_t i = 0; i < _num_buckets; i++) {
    +    _buckets[i] = nullptr;
    +  }
    +
    +  size_t new_capacity = bucket_size(0);
     
    -  return resize(initial_chunk_capacity);
    +  if (!reserve(new_capacity)) {
    +    log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(TaskQueueEntryChunk));
    +    return false;
    +  }
    +  return true;
     }
     
    -void G1CMMarkStack::expand() {
    -  if (_chunk_capacity == _max_chunk_capacity) {
    -    log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity);
    -    return;
    +bool G1CMMarkStack::ChunkAllocator::expand() {
    +  if (_capacity == _max_capacity) {
    +    log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _capacity);
    +    return false;
       }
    -  size_t old_capacity = _chunk_capacity;
    -  // Double capacity if possible
    -  size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity);
    +  size_t old_capacity = _capacity;
    +  // Double capacity if possible.
    +  size_t new_capacity = MIN2(old_capacity * 2, _max_capacity);
     
    -  if (resize(new_capacity)) {
    -    log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
    +  if (reserve(new_capacity)) {
    +    log_debug(gc)("Expanded the mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
                       old_capacity, new_capacity);
    -  } else {
    -    log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
    -                    old_capacity, new_capacity);
    +    return true;
    +  }
    +  return false;
    +}
    +
    +G1CMMarkStack::ChunkAllocator::~ChunkAllocator() {
    +  if (_buckets == nullptr) {
    +    return;
       }
    +
    +  for (size_t i = 0; i < _num_buckets; i++) {
    +    if (_buckets[i] != nullptr) {
    +      MmapArrayAllocator::free(_buckets[i],  bucket_size(i));
    +      _buckets[i] = nullptr;
    +    }
    +  }
    +
    +  FREE_C_HEAP_ARRAY(TaskQueueEntryChunk*, _buckets);
     }
     
    -G1CMMarkStack::~G1CMMarkStack() {
    -  if (_base != nullptr) {
    -    MmapArrayAllocator::free(_base, _chunk_capacity);
    +bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) {
    +  assert(new_capacity <= _max_capacity, "Cannot expand overflow mark stack beyond the max_capacity" SIZE_FORMAT " chunks.", _max_capacity);
    +
    +  size_t highest_bucket = get_bucket(new_capacity - 1);
    +  size_t i = get_bucket(_capacity);
    +
    +  for (; i <= highest_bucket; i++) {
    +    if (Atomic::load_acquire(&_buckets[i]) != nullptr) {
    +      continue; // Skip over already allocated buckets.
    +    }
    +
    +    size_t bucket_capacity = bucket_size(i);
    +
    +    // Trim bucket size so that we do not exceed the _max_capacity.
    +    bucket_capacity = (_capacity + bucket_capacity) <= _max_capacity ?
    +                      bucket_capacity :
    +                      _max_capacity - _capacity;
    +
    +
    +    TaskQueueEntryChunk* bucket_base = MmapArrayAllocator::allocate_or_null(bucket_capacity, mtGC);
    +
    +    if (bucket_base == nullptr) {
    +      log_warning(gc)("Failed to reserve memory for increasing the overflow mark stack capacity with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.",
    +                      bucket_capacity, bucket_capacity * sizeof(TaskQueueEntryChunk));
    +      return false;
    +    }
    +    _capacity += bucket_capacity;
    +    Atomic::release_store(&_buckets[i], bucket_base);
       }
    +  return true;
    +}
    +
    +void G1CMMarkStack::expand() {
    +  _chunk_allocator.expand();
     }
     
     void G1CMMarkStack::add_chunk_to_list(TaskQueueEntryChunk* volatile* list, TaskQueueEntryChunk* elem) {
    @@ -208,31 +302,13 @@ G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::remove_chunk_from_free_list()
       return remove_chunk_from_list(&_free_list);
     }
     
    -G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::allocate_new_chunk() {
    -  // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code.
    -  // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding
    -  // wraparound of _hwm.
    -  if (_hwm >= _chunk_capacity) {
    -    return nullptr;
    -  }
    -
    -  size_t cur_idx = Atomic::fetch_then_add(&_hwm, 1u);
    -  if (cur_idx >= _chunk_capacity) {
    -    return nullptr;
    -  }
    -
    -  TaskQueueEntryChunk* result = ::new (&_base[cur_idx]) TaskQueueEntryChunk;
    -  result->next = nullptr;
    -  return result;
    -}
    -
     bool G1CMMarkStack::par_push_chunk(G1TaskQueueEntry* ptr_arr) {
       // Get a new chunk.
       TaskQueueEntryChunk* new_chunk = remove_chunk_from_free_list();
     
       if (new_chunk == nullptr) {
         // Did not get a chunk from the free list. Allocate from backing memory.
    -    new_chunk = allocate_new_chunk();
    +    new_chunk = _chunk_allocator.allocate_new_chunk();
     
         if (new_chunk == nullptr) {
           return false;
    @@ -261,9 +337,9 @@ bool G1CMMarkStack::par_pop_chunk(G1TaskQueueEntry* ptr_arr) {
     
     void G1CMMarkStack::set_empty() {
       _chunks_in_chunk_list = 0;
    -  _hwm = 0;
       _chunk_list = nullptr;
       _free_list = nullptr;
    +  _chunk_allocator.reset();
     }
     
     G1CMRootMemRegions::G1CMRootMemRegions(uint const max_regions) :
    @@ -440,7 +516,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
       _concurrent_workers->initialize_workers();
       _num_concurrent_workers = _concurrent_workers->active_workers();
     
    -  if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) {
    +  if (!_global_mark_stack.initialize()) {
         vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack.");
       }
     
    @@ -1635,6 +1711,9 @@ void G1ConcurrentMark::weak_refs_work() {
     
         assert(_global_mark_stack.is_empty(), "mark stack should be empty");
     
    +    // Prefer to grow the stack until the max capacity.
    +    _global_mark_stack.set_should_grow();
    +
         // We need at least one active thread. If reference processing
         // is not multi-threaded we use the current (VMThread) thread,
         // otherwise we use the workers from the G1CollectedHeap and
    diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
    index 4799f32e0c8..a4315ec5f6c 100644
    --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
    +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
    @@ -136,24 +136,108 @@ class G1CMMarkStack {
         G1TaskQueueEntry data[EntriesPerChunk];
       };
     
    -  size_t _max_chunk_capacity;    // Maximum number of TaskQueueEntryChunk elements on the stack.
    +  class ChunkAllocator {
    +    // The chunk allocator relies on a growable array data structure that allows resizing without the
    +    // need to copy existing items. The basic approach involves organizing the array into chunks,
    +    // essentially creating an "array of arrays"; referred to as buckets in this implementation. To
    +    // facilitate efficient indexing, the size of the first bucket is set to a power of 2. This choice
    +    // allows for quick conversion of an array index into a bucket index and the corresponding offset
    +    // within the bucket. Additionally, each new bucket added to the growable array doubles the capacity of
    +    // the growable array.
    +    //
    +    // Illustration of the Growable Array data structure.
    +    //
    +    //        +----+        +----+----+
    +    //        |    |------->|    |    |
    +    //        |    |        +----+----+
    +    //        +----+        +----+----+
    +    //        |    |------->|    |    |
    +    //        |    |        +----+----+
    +    //        +----+        +-----+-----+-----+-----+
    +    //        |    |------->|     |     |     |     |
    +    //        |    |        +-----+-----+-----+-----+
    +    //        +----+        +-----+-----+-----+-----+-----+-----+-----+----+
    +    //        |    |------->|     |     |     |     |     |     |     |    |
    +    //        |    |        +-----+-----+-----+-----+-----+-----+-----+----+
    +    //        +----+
    +    //
    +    size_t _min_capacity;
    +    size_t _max_capacity;
    +    size_t _capacity;
    +    size_t _num_buckets;
    +    bool _should_grow;
    +    TaskQueueEntryChunk* volatile* _buckets;
    +    char _pad0[DEFAULT_PADDING_SIZE];
    +    volatile size_t _size;
    +    char _pad4[DEFAULT_PADDING_SIZE - sizeof(size_t)];
    +
    +    size_t bucket_size(size_t bucket) {
    +      return (bucket == 0) ?
    +              _min_capacity :
    +              _min_capacity * ( 1ULL << (bucket -1));
    +    }
    +
    +    static unsigned int find_highest_bit(uintptr_t mask) {
    +      return count_leading_zeros(mask) ^ (BitsPerWord - 1U);
    +    }
    +
    +    size_t get_bucket(size_t array_idx) {
    +      if (array_idx < _min_capacity) {
    +        return 0;
    +      }
     
    -  TaskQueueEntryChunk* _base;    // Bottom address of allocated memory area.
    -  size_t _chunk_capacity;        // Current maximum number of TaskQueueEntryChunk elements.
    +      return find_highest_bit(array_idx) - find_highest_bit(_min_capacity) + 1;
    +    }
    +
    +    size_t get_bucket_index(size_t array_idx) {
    +      if (array_idx < _min_capacity) {
    +        return array_idx;
    +      }
    +      return array_idx - (1ULL << find_highest_bit(array_idx));
    +    }
    +
    +    bool reserve(size_t new_capacity);
    +
    +  public:
    +    ChunkAllocator();
    +
    +    ~ChunkAllocator();
    +
    +    bool initialize(size_t initial_capacity, size_t max_capacity);
    +
    +    void reset() {
    +      _size = 0;
    +      _should_grow = false;
    +    }
     
    -  char _pad0[DEFAULT_CACHE_LINE_SIZE];
    +    // During G1CMConcurrentMarkingTask or finalize_marking phases, we prefer to restart the marking when
    +    // the G1CMMarkStack overflows. Attempts to expand the G1CMMarkStack should be followed with a restart
    +    // of the marking. On failure to allocate a new chuck, the caller just returns and forces a restart.
    +    // This approach offers better memory utilization for the G1CMMarkStack, as each iteration of the
    +    // marking potentially involves traversing fewer unmarked nodes in the graph.
    +
    +    // However, during the reference processing phase, instead of restarting the marking process, the
    +    // G1CMMarkStack is expanded upon failure to allocate a new chunk. The decision between these two
    +    // modes of expansion is determined by the _should_grow parameter.
    +    void set_should_grow() {
    +      _should_grow = true;
    +    }
    +
    +    size_t capacity() const { return _capacity; }
    +
    +    bool expand();
    +
    +    TaskQueueEntryChunk* allocate_new_chunk();
    +  };
    +
    +  ChunkAllocator _chunk_allocator;
    +
    +  char _pad0[DEFAULT_PADDING_SIZE];
       TaskQueueEntryChunk* volatile _free_list;  // Linked list of free chunks that can be allocated by users.
    -  char _pad1[DEFAULT_CACHE_LINE_SIZE - sizeof(TaskQueueEntryChunk*)];
    +  char _pad1[DEFAULT_PADDING_SIZE - sizeof(TaskQueueEntryChunk*)];
       TaskQueueEntryChunk* volatile _chunk_list; // List of chunks currently containing data.
       volatile size_t _chunks_in_chunk_list;
    -  char _pad2[DEFAULT_CACHE_LINE_SIZE - sizeof(TaskQueueEntryChunk*) - sizeof(size_t)];
    -
    -  volatile size_t _hwm;          // High water mark within the reserved space.
    -  char _pad4[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)];
    -
    -  // Allocate a new chunk from the reserved memory, using the high water mark. Returns
    -  // null if out of memory.
    -  TaskQueueEntryChunk* allocate_new_chunk();
    +  char _pad2[DEFAULT_PADDING_SIZE - sizeof(TaskQueueEntryChunk*) - sizeof(size_t)];
     
       // Atomically add the given chunk to the list.
       void add_chunk_to_list(TaskQueueEntryChunk* volatile* list, TaskQueueEntryChunk* elem);
    @@ -167,19 +251,15 @@ class G1CMMarkStack {
       TaskQueueEntryChunk* remove_chunk_from_chunk_list();
       TaskQueueEntryChunk* remove_chunk_from_free_list();
     
    -  // Resizes the mark stack to the given new capacity. Releases any previous
    -  // memory if successful.
    -  bool resize(size_t new_capacity);
    -
      public:
       G1CMMarkStack();
    -  ~G1CMMarkStack();
    +  ~G1CMMarkStack() = default;
     
       // Alignment and minimum capacity of this mark stack in number of oops.
       static size_t capacity_alignment();
     
    -  // Allocate and initialize the mark stack with the given number of oops.
    -  bool initialize(size_t initial_capacity, size_t max_capacity);
    +  // Allocate and initialize the mark stack.
    +  bool initialize();
     
       // Pushes the given buffer containing at most EntriesPerChunk elements on the mark
       // stack. If less than EntriesPerChunk elements are to be pushed, the array must
    @@ -197,7 +277,11 @@ class G1CMMarkStack {
       // _chunk_list.
       bool is_empty() const { return _chunk_list == nullptr; }
     
    -  size_t capacity() const  { return _chunk_capacity; }
    +  size_t capacity() const  { return _chunk_allocator.capacity(); }
    +
    +  void set_should_grow() {
    +    _chunk_allocator.set_should_grow();
    +  }
     
       // Expand the stack, typically in response to an overflow condition
       void expand();
    diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp
    index aebdd2c43f5..b2ac4b25e90 100644
    --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp
    +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp
    @@ -58,56 +58,46 @@ G1ConcurrentRefineThread* G1ConcurrentRefineThreadControl::create_refinement_thr
       return result;
     }
     
    -G1ConcurrentRefineThreadControl::G1ConcurrentRefineThreadControl() :
    +G1ConcurrentRefineThreadControl::G1ConcurrentRefineThreadControl(uint max_num_threads) :
       _cr(nullptr),
    -  _threads(nullptr),
    -  _max_num_threads(0)
    +  _threads(max_num_threads)
     {}
     
     G1ConcurrentRefineThreadControl::~G1ConcurrentRefineThreadControl() {
    -  if (_threads != nullptr) {
    -    for (uint i = 0; i < _max_num_threads; i++) {
    -      G1ConcurrentRefineThread* t = _threads[i];
    -      if (t == nullptr) {
    -#ifdef ASSERT
    -        for (uint j = i + 1; j < _max_num_threads; ++j) {
    -          assert(_threads[j] == nullptr, "invariant");
    -        }
    -#endif // ASSERT
    -        break;
    -      } else {
    -        delete t;
    -      }
    +  while (_threads.is_nonempty()) {
    +    delete _threads.pop();
    +  }
    +}
    +
    +bool G1ConcurrentRefineThreadControl::ensure_threads_created(uint worker_id, bool initializing) {
    +  assert(worker_id < max_num_threads(), "precondition");
    +
    +  while ((uint)_threads.length() <= worker_id) {
    +    G1ConcurrentRefineThread* rt = create_refinement_thread(_threads.length(), initializing);
    +    if (rt == nullptr) {
    +      return false;
         }
    -    FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads);
    +    _threads.push(rt);
       }
    +
    +  return true;
     }
     
    -jint G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cr, uint max_num_threads) {
    +jint G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cr) {
       assert(cr != nullptr, "G1ConcurrentRefine must not be null");
       _cr = cr;
    -  _max_num_threads = max_num_threads;
    -
    -  if (max_num_threads > 0) {
    -    _threads = NEW_C_HEAP_ARRAY(G1ConcurrentRefineThread*, max_num_threads, mtGC);
     
    -    _threads[0] = create_refinement_thread(0, true);
    -    if (_threads[0] == nullptr) {
    +  if (max_num_threads() > 0) {
    +    _threads.push(create_refinement_thread(0, true));
    +    if (_threads.at(0) == nullptr) {
           vm_shutdown_during_initialization("Could not allocate primary refinement thread");
           return JNI_ENOMEM;
         }
     
    -    if (UseDynamicNumberOfGCThreads) {
    -      for (uint i = 1; i < max_num_threads; ++i) {
    -        _threads[i] = nullptr;
    -      }
    -    } else {
    -      for (uint i = 1; i < max_num_threads; ++i) {
    -        _threads[i] = create_refinement_thread(i, true);
    -        if (_threads[i] == nullptr) {
    -          vm_shutdown_during_initialization("Could not allocate refinement threads.");
    -          return JNI_ENOMEM;
    -        }
    +    if (!UseDynamicNumberOfGCThreads) {
    +      if (!ensure_threads_created(max_num_threads() - 1, true)) {
    +        vm_shutdown_during_initialization("Could not allocate refinement threads");
    +        return JNI_ENOMEM;
           }
         }
       }
    @@ -117,38 +107,28 @@ jint G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cr, uint ma
     
     #ifdef ASSERT
     void G1ConcurrentRefineThreadControl::assert_current_thread_is_primary_refinement_thread() const {
    -  assert(_threads != nullptr, "No threads");
    -  assert(Thread::current() == _threads[0], "Not primary thread");
    +  assert(Thread::current() == _threads.at(0), "Not primary thread");
     }
     #endif // ASSERT
     
     bool G1ConcurrentRefineThreadControl::activate(uint worker_id) {
    -  assert(worker_id < _max_num_threads, "precondition");
    -  G1ConcurrentRefineThread* thread_to_activate = _threads[worker_id];
    -  if (thread_to_activate == nullptr) {
    -    thread_to_activate = create_refinement_thread(worker_id, false);
    -    if (thread_to_activate == nullptr) {
    -      return false;
    -    }
    -    _threads[worker_id] = thread_to_activate;
    +  if (ensure_threads_created(worker_id, false)) {
    +    _threads.at(worker_id)->activate();
    +    return true;
       }
    -  thread_to_activate->activate();
    -  return true;
    +
    +  return false;
     }
     
     void G1ConcurrentRefineThreadControl::worker_threads_do(ThreadClosure* tc) {
    -  for (uint i = 0; i < _max_num_threads; i++) {
    -    if (_threads[i] != nullptr) {
    -      tc->do_thread(_threads[i]);
    -    }
    +  for (G1ConcurrentRefineThread* t : _threads) {
    +    tc->do_thread(t);
       }
     }
     
     void G1ConcurrentRefineThreadControl::stop() {
    -  for (uint i = 0; i < _max_num_threads; i++) {
    -    if (_threads[i] != nullptr) {
    -      _threads[i]->stop();
    -    }
    +  for (G1ConcurrentRefineThread* t : _threads) {
    +    t->stop();
       }
     }
     
    @@ -170,12 +150,12 @@ G1ConcurrentRefine::G1ConcurrentRefine(G1Policy* policy) :
       _last_adjust(),
       _needs_adjust(false),
       _threads_needed(policy, adjust_threads_period_ms()),
    -  _thread_control(),
    +  _thread_control(G1ConcRefinementThreads),
       _dcqs(G1BarrierSet::dirty_card_queue_set())
     {}
     
     jint G1ConcurrentRefine::initialize() {
    -  return _thread_control.initialize(this, max_num_threads());
    +  return _thread_control.initialize(this);
     }
     
     G1ConcurrentRefine* G1ConcurrentRefine::create(G1Policy* policy, jint* ecode) {
    @@ -199,10 +179,6 @@ void G1ConcurrentRefine::threads_do(ThreadClosure *tc) {
       _thread_control.worker_threads_do(tc);
     }
     
    -uint G1ConcurrentRefine::max_num_threads() {
    -  return G1ConcRefinementThreads;
    -}
    -
     void G1ConcurrentRefine::update_pending_cards_target(double logged_cards_time_ms,
                                                          size_t processed_logged_cards,
                                                          size_t predicted_thread_buffer_cards,
    diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp
    index 30a8fe7f757..dd0b62a22ea 100644
    --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp
    +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp
    @@ -30,6 +30,7 @@
     #include "memory/allocation.hpp"
     #include "utilities/debug.hpp"
     #include "utilities/globalDefinitions.hpp"
    +#include "utilities/growableArray.hpp"
     #include "utilities/macros.hpp"
     
     // Forward decl
    @@ -43,24 +44,25 @@ class ThreadClosure;
     // iterate over them.
     class G1ConcurrentRefineThreadControl {
       G1ConcurrentRefine* _cr;
    -  G1ConcurrentRefineThread** _threads;
    -  uint _max_num_threads;
    +  GrowableArrayCHeap _threads;
     
       // Create the refinement thread for the given worker id.
       // If initializing is true, ignore InjectGCWorkerCreationFailure.
       G1ConcurrentRefineThread* create_refinement_thread(uint worker_id, bool initializing);
     
    +  bool ensure_threads_created(uint worker_id, bool initializing);
    +
       NONCOPYABLE(G1ConcurrentRefineThreadControl);
     
     public:
    -  G1ConcurrentRefineThreadControl();
    +  G1ConcurrentRefineThreadControl(uint max_num_threads);
       ~G1ConcurrentRefineThreadControl();
     
    -  jint initialize(G1ConcurrentRefine* cr, uint max_num_threads);
    +  jint initialize(G1ConcurrentRefine* cr);
     
       void assert_current_thread_is_primary_refinement_thread() const NOT_DEBUG_RETURN;
     
    -  uint max_num_threads() const { return _max_num_threads; }
    +  uint max_num_threads() const { return _threads.capacity(); }
     
       // Activate the indicated thread.  If the thread has not yet been allocated,
       // allocate and then activate.  If allocation is needed and fails, return
    @@ -215,9 +217,6 @@ class G1ConcurrentRefine : public CHeapObj {
     
       // Iterate over all concurrent refinement threads applying the given closure.
       void threads_do(ThreadClosure *tc);
    -
    -  // Maximum number of refinement threads.
    -  static uint max_num_threads();
     };
     
     #endif // SHARE_GC_G1_G1CONCURRENTREFINE_HPP
    diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp
    index bf25e3828d1..1dd3a9aface 100644
    --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp
    +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp
    @@ -135,7 +135,7 @@ class G1DirtyCardQueueSet: public PtrQueueSet {
         // and install the next list, and meanwhile there can be a thread dealing
         // with the previous list.
         PausedList* volatile _plist;
    -    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(PausedList*));
    +    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(PausedList*));
     
         NONCOPYABLE(PausedBuffers);
     
    @@ -157,19 +157,19 @@ class G1DirtyCardQueueSet: public PtrQueueSet {
         HeadTail take_all();
       };
     
    -  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
       // Upper bound on the number of cards in the completed and paused buffers.
       volatile size_t _num_cards;
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t));
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(size_t));
       // If the queue contains more cards than configured here, the
       // mutator must start doing some of the concurrent refinement work.
       volatile size_t _mutator_refinement_threshold;
    -  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t));
    +  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, sizeof(size_t));
       // Buffers ready for refinement.
       // NonblockingQueue has inner padding of one cache line.
       NonblockingQueue _completed;
       // Add a trailer padding after NonblockingQueue.
    -  DEFINE_PAD_MINUS_SIZE(3, DEFAULT_CACHE_LINE_SIZE, sizeof(BufferNode*));
    +  DEFINE_PAD_MINUS_SIZE(3, DEFAULT_PADDING_SIZE, sizeof(BufferNode*));
       // Buffers for which refinement is temporarily paused.
       // PausedBuffers has inner padding, including trailer.
       PausedBuffers _paused;
    diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.cpp b/src/hotspot/share/gc/g1/g1FromCardCache.cpp
    index d3e7af768b5..062130f40ab 100644
    --- a/src/hotspot/share/gc/g1/g1FromCardCache.cpp
    +++ b/src/hotspot/share/gc/g1/g1FromCardCache.cpp
    @@ -81,7 +81,7 @@ void G1FromCardCache::print(outputStream* out) {
     #endif
     
     uint G1FromCardCache::num_par_rem_sets() {
    -  return G1DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::max_num_threads() + MAX2(ConcGCThreads, ParallelGCThreads);
    +  return G1DirtyCardQueueSet::num_par_ids() + G1ConcRefinementThreads + MAX2(ConcGCThreads, ParallelGCThreads);
     }
     
     void G1FromCardCache::clear(uint region_idx) {
    diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp
    index a2097041b20..4f759b4a606 100644
    --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp
    +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp
    @@ -62,7 +62,7 @@ G1HeapTransition::Data::~Data() {
     
     G1HeapTransition::G1HeapTransition(G1CollectedHeap* g1_heap) : _g1_heap(g1_heap), _before(g1_heap) { }
     
    -struct DetailedUsage : public StackObj {
    +struct G1HeapTransition::DetailedUsage : public StackObj {
       size_t _eden_used;
       size_t _survivor_used;
       size_t _old_used;
    @@ -79,7 +79,7 @@ struct DetailedUsage : public StackObj {
         _humongous_region_count(0) {}
     };
     
    -class DetailedUsageClosure: public HeapRegionClosure {
    +class G1HeapTransition::DetailedUsageClosure: public HeapRegionClosure {
     public:
       DetailedUsage _usage;
       bool do_heap_region(HeapRegion* r) {
    diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.hpp b/src/hotspot/share/gc/g1/g1HeapTransition.hpp
    index 09d901f283c..54f87fd3b71 100644
    --- a/src/hotspot/share/gc/g1/g1HeapTransition.hpp
    +++ b/src/hotspot/share/gc/g1/g1HeapTransition.hpp
    @@ -31,6 +31,9 @@
     class G1CollectedHeap;
     
     class G1HeapTransition {
    +  struct DetailedUsage;
    +  class DetailedUsageClosure;
    +
       struct Data {
         size_t _eden_length;
         size_t _survivor_length;
    diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.hpp b/src/hotspot/share/gc/g1/g1MonotonicArena.hpp
    index 8a6bb88e008..586766a8c8f 100644
    --- a/src/hotspot/share/gc/g1/g1MonotonicArena.hpp
    +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.hpp
    @@ -125,7 +125,7 @@ class G1MonotonicArena::Segment {
       char* _bottom;  // Actual data.
       // Do not add class member variables beyond this point
     
    -  static size_t header_size() { return align_up(sizeof(Segment), DEFAULT_CACHE_LINE_SIZE); }
    +  static size_t header_size() { return align_up(sizeof(Segment), DEFAULT_PADDING_SIZE); }
     
       static size_t payload_size(uint slot_size, uint num_slots) {
         // The cast (size_t) is required to guard against overflow wrap around.
    diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
    index 1f3348614b1..8063d9652aa 100644
    --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
    +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
    @@ -95,7 +95,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
       // entries, since entry 0 keeps track of surviving bytes for non-young regions.
       // We also add a few elements at the beginning and at the end in
       // an attempt to eliminate cache contention
    -  const size_t padding_elem_num = (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t));
    +  const size_t padding_elem_num = (DEFAULT_PADDING_SIZE / sizeof(size_t));
       size_t array_length = padding_elem_num + _surviving_words_length + padding_elem_num;
     
       _surviving_young_words_base = NEW_C_HEAP_ARRAY(size_t, array_length, mtGC);
    diff --git a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp
    index f270e31f772..970cce1623e 100644
    --- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp
    +++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp
    @@ -66,11 +66,11 @@ class G1RedirtyCardsLocalQueueSet : private PtrQueueSet {
     // collected (and processed) buffers reverts back to collecting, allowing
     // the set to be reused for another round of redirtying.
     class G1RedirtyCardsQueueSet : public PtrQueueSet {
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, 0);
       BufferNode::Stack _list;
    -  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t));
    +  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, sizeof(size_t));
       volatile size_t _entry_count;
    -  DEFINE_PAD_MINUS_SIZE(3, DEFAULT_CACHE_LINE_SIZE, sizeof(BufferNode*));
    +  DEFINE_PAD_MINUS_SIZE(3, DEFAULT_PADDING_SIZE, sizeof(BufferNode*));
       BufferNode* _tail;
       DEBUG_ONLY(mutable bool _collecting;)
     
    diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp
    index 2ff7e835d33..ac445850085 100644
    --- a/src/hotspot/share/gc/g1/g1RemSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp
    @@ -91,11 +91,6 @@ class G1RemSetScanState : public CHeapObj {
     
       size_t _max_reserved_regions;
     
    -  // Has this region that is part of the regions in the collection set been processed yet.
    -  typedef bool G1RemsetIterState;
    -
    -  G1RemsetIterState volatile* _collection_set_iter_state;
    -
       // Card table iteration claim for each heap region, from 0 (completely unscanned)
       // to (>=) HeapRegion::CardsPerRegion (completely scanned).
       uint volatile* _card_table_scan_state;
    diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp
    index cedbefe1fe8..4156e85fbfa 100644
    --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp
    +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp
    @@ -67,7 +67,7 @@ double G1RemSetSummary::rs_thread_vtime(uint thread) const {
     }
     
     G1RemSetSummary::G1RemSetSummary(bool should_update) :
    -  _num_vtimes(G1ConcurrentRefine::max_num_threads()),
    +  _num_vtimes(G1ConcRefinementThreads),
       _rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)) {
     
       memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes);
    diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp
    index 6c084a72d94..c227b625b8d 100644
    --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp
    +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp
    @@ -38,18 +38,16 @@ bool G1RemSetTrackingPolicy::needs_scan_for_rebuild(HeapRegion* r) const {
     }
     
     void G1RemSetTrackingPolicy::update_at_allocate(HeapRegion* r) {
    -  if (r->is_young()) {
    -    // Always collect remembered set for young regions.
    -    r->rem_set()->set_state_complete();
    -  } else if (r->is_humongous()) {
    -    // Collect remembered sets for humongous regions by default to allow eager reclaim.
    -    r->rem_set()->set_state_complete();
    -  } else if (r->is_old()) {
    +  assert(r->is_young() || r->is_humongous() || r->is_old(),
    +        "Region %u with unexpected heap region type %s", r->hrm_index(), r->get_type_str());
    +  if (r->is_old()) {
         // By default, do not create remembered set for new old regions.
         r->rem_set()->set_state_untracked();
    -  } else {
    -    guarantee(false, "Unhandled region %u with heap region type %s", r->hrm_index(), r->get_type_str());
    +    return;
       }
    +  // Always collect remembered set for young regions and for humongous regions.
    +  // Humongous regions need that for eager reclaim.
    +  r->rem_set()->set_state_complete();
     }
     
     void G1RemSetTrackingPolicy::update_at_free(HeapRegion* r) {
    diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp
    index c46c1b47332..5f7f3a27d5b 100644
    --- a/src/hotspot/share/gc/g1/g1_globals.hpp
    +++ b/src/hotspot/share/gc/g1/g1_globals.hpp
    @@ -113,11 +113,11 @@
               "of the optimal occupancy to start marking.")                     \
               range(1, max_intx)                                                \
                                                                                 \
    -  product(uint, G1ConfidencePercent, 50,                                   \
    +  product(uint, G1ConfidencePercent, 50,                                    \
               "Confidence level for MMU/pause predictions")                     \
               range(0, 100)                                                     \
                                                                                 \
    -  product(intx, G1SummarizeRSetStatsPeriod, 0, DIAGNOSTIC,                  \
    +  product(uintx, G1SummarizeRSetStatsPeriod, 0, DIAGNOSTIC,                 \
               "The period (in number of GCs) at which we will generate "        \
               "update buffer processing info "                                  \
               "(0 means do not periodically generate this info); "              \
    @@ -148,7 +148,7 @@
               "Number of entries in an SATB log buffer.")                       \
               constraint(G1SATBBufferSizeConstraintFunc, AtParse)               \
                                                                                 \
    -  develop(intx, G1SATBProcessCompletedThreshold, 20,                        \
    +  develop(uintx, G1SATBProcessCompletedThreshold, 20,                       \
               "Number of completed buffers that triggers log processing.")      \
               range(0, max_jint)                                                \
                                                                                 \
    diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp
    index 41cce2fa661..19b383a08a3 100644
    --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp
    +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp
    @@ -115,6 +115,10 @@ void HeapRegionRemSet::remove_code_root(nmethod* nm) {
       guarantee(!_code_roots.contains(nm), "duplicate entry found");
     }
     
    +void HeapRegionRemSet::bulk_remove_code_roots() {
    +  _code_roots.bulk_remove();
    +}
    +
     void HeapRegionRemSet::code_roots_do(CodeBlobClosure* blk) const {
       _code_roots.nmethods_do(blk);
     }
    diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp
    index d75f52baa95..2e5ae7b1c30 100644
    --- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp
    +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp
    @@ -150,6 +150,7 @@ class HeapRegionRemSet : public CHeapObj {
       // the heap region that owns this RSet.
       void add_code_root(nmethod* nm);
       void remove_code_root(nmethod* nm);
    +  void bulk_remove_code_roots();
     
       // Applies blk->do_code_blob() to each of the entries in _code_roots
       void code_roots_do(CodeBlobClosure* blk) const;
    diff --git a/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp b/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp
    index 57b48d49f95..e83813c78f4 100644
    --- a/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp
    +++ b/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp
    @@ -60,7 +60,6 @@ class GCAdaptivePolicyCounters : public GCPolicyCounters {
       PerfVariable*         _decrease_for_footprint_counter;
     
       PerfVariable*         _minor_pause_young_slope_counter;
    -  PerfVariable*         _major_pause_old_slope_counter;
     
       PerfVariable*         _decide_at_full_gc_counter;
     
    diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp
    index 77ecb4da466..18271fabd05 100644
    --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp
    +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp
    @@ -184,8 +184,6 @@ class MutableNUMASpace : public MutableSpace {
       virtual size_t used_in_words() const;
       virtual size_t free_in_words() const;
     
    -  using MutableSpace::capacity_in_words;
    -
       virtual size_t tlab_capacity(Thread* thr) const;
       virtual size_t tlab_used(Thread* thr) const;
       virtual size_t unsafe_max_tlab_alloc(Thread* thr) const;
    diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
    index 748a5658843..2531ecb2d5c 100644
    --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
    +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
    @@ -532,6 +532,14 @@ void ParallelScavengeHeap::resize_all_tlabs() {
       CollectedHeap::resize_all_tlabs();
     }
     
    +void ParallelScavengeHeap::prune_scavengable_nmethods() {
    +  ScavengableNMethods::prune_nmethods_not_into_young();
    +}
    +
    +void ParallelScavengeHeap::prune_unlinked_nmethods() {
    +  ScavengableNMethods::prune_unlinked_nmethods();
    +}
    +
     // This method is used by System.gc() and JVMTI.
     void ParallelScavengeHeap::collect(GCCause::Cause cause) {
       assert(!Heap_lock->owned_by_self(),
    @@ -863,10 +871,6 @@ void ParallelScavengeHeap::verify_nmethod(nmethod* nm) {
       ScavengableNMethods::verify_nmethod(nm);
     }
     
    -void ParallelScavengeHeap::prune_scavengable_nmethods() {
    -  ScavengableNMethods::prune_nmethods();
    -}
    -
     GrowableArray ParallelScavengeHeap::memory_managers() {
       GrowableArray memory_managers(2);
       memory_managers.append(_young_manager);
    diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
    index d30effd5e5b..eec32a2c1c2 100644
    --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
    +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
    @@ -176,6 +176,7 @@ class ParallelScavengeHeap : public CollectedHeap {
       void verify_nmethod(nmethod* nm) override;
     
       void prune_scavengable_nmethods();
    +  void prune_unlinked_nmethods();
     
       size_t max_capacity() const override;
     
    diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp
    index 3e255c15a4e..be6d9a501b5 100644
    --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp
    +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp
    @@ -51,7 +51,6 @@ PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t init_eden_size,
          _avg_major_pause(new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding)),
          _avg_base_footprint(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),
          _gc_stats(),
    -     _collection_cost_margin_fraction(AdaptiveSizePolicyCollectionCostMargin / 100.0),
          _major_pause_old_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
          _major_pause_young_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
          _latest_major_mutator_interval_seconds(0),
    @@ -281,11 +280,11 @@ void PSAdaptiveSizePolicy::compute_eden_space_size(
         //
         // Make changes only to affect one of the pauses (the larger)
         // at a time.
    -    adjust_eden_for_pause_time(is_full_gc, &desired_promo_size, &desired_eden_size);
    +    adjust_eden_for_pause_time(&desired_eden_size);
     
       } else if (_avg_minor_pause->padded_average() > gc_minor_pause_goal_sec()) {
         // Adjust only for the minor pause time goal
    -    adjust_eden_for_minor_pause_time(is_full_gc, &desired_eden_size);
    +    adjust_eden_for_minor_pause_time(&desired_eden_size);
     
       } else if(adjusted_mutator_cost() < _throughput_goal) {
         // This branch used to require that (mutator_cost() > 0.0 in 1.4.2.
    @@ -456,7 +455,7 @@ void PSAdaptiveSizePolicy::compute_old_gen_free_space(
         // at a time.
         if (is_full_gc) {
           set_decide_at_full_gc(decide_at_full_gc_true);
    -      adjust_promo_for_pause_time(is_full_gc, &desired_promo_size, &desired_eden_size);
    +      adjust_promo_for_pause_time(&desired_promo_size);
         }
       } else if (adjusted_mutator_cost() < _throughput_goal) {
         // This branch used to require that (mutator_cost() > 0.0 in 1.4.2.
    @@ -571,9 +570,7 @@ void PSAdaptiveSizePolicy::decay_supplemental_growth(bool is_full_gc) {
       }
     }
     
    -void PSAdaptiveSizePolicy::adjust_eden_for_minor_pause_time(bool is_full_gc,
    -    size_t* desired_eden_size_ptr) {
    -
    +void PSAdaptiveSizePolicy::adjust_eden_for_minor_pause_time(size_t* desired_eden_size_ptr) {
       // Adjust the young generation size to reduce pause time of
       // of collections.
       //
    @@ -586,25 +583,23 @@ void PSAdaptiveSizePolicy::adjust_eden_for_minor_pause_time(bool is_full_gc,
               decrease_young_gen_for_min_pauses_true);
         *desired_eden_size_ptr = *desired_eden_size_ptr -
           eden_decrement_aligned_down(*desired_eden_size_ptr);
    -    } else {
    -      // EXPERIMENTAL ADJUSTMENT
    -      // Only record that the estimator indicated such an action.
    -      // *desired_eden_size_ptr = *desired_eden_size_ptr + eden_heap_delta;
    -      set_change_young_gen_for_min_pauses(
    -          increase_young_gen_for_min_pauses_true);
    +  } else {
    +    // EXPERIMENTAL ADJUSTMENT
    +    // Only record that the estimator indicated such an action.
    +    // *desired_eden_size_ptr = *desired_eden_size_ptr + eden_heap_delta;
    +    set_change_young_gen_for_min_pauses(
    +      increase_young_gen_for_min_pauses_true);
       }
     }
     
    -void PSAdaptiveSizePolicy::adjust_promo_for_pause_time(bool is_full_gc,
    -                                             size_t* desired_promo_size_ptr,
    -                                             size_t* desired_eden_size_ptr) {
    +void PSAdaptiveSizePolicy::adjust_promo_for_pause_time(size_t* desired_promo_size_ptr) {
     
       size_t promo_heap_delta = 0;
       // Add some checks for a threshold for a change.  For example,
       // a change less than the required alignment is probably not worth
       // attempting.
     
    -  if (_avg_minor_pause->padded_average() <= _avg_major_pause->padded_average() && is_full_gc) {
    +  if (_avg_minor_pause->padded_average() <= _avg_major_pause->padded_average()) {
         // Adjust for the major pause time only at full gc's because the
         // affects of a change can only be seen at full gc's.
     
    @@ -631,16 +626,14 @@ void PSAdaptiveSizePolicy::adjust_promo_for_pause_time(bool is_full_gc,
         *desired_promo_size_ptr, promo_heap_delta);
     }
     
    -void PSAdaptiveSizePolicy::adjust_eden_for_pause_time(bool is_full_gc,
    -                                             size_t* desired_promo_size_ptr,
    -                                             size_t* desired_eden_size_ptr) {
    +void PSAdaptiveSizePolicy::adjust_eden_for_pause_time(size_t* desired_eden_size_ptr) {
     
       size_t eden_heap_delta = 0;
       // Add some checks for a threshold for a change.  For example,
       // a change less than the required alignment is probably not worth
       // attempting.
       if (_avg_minor_pause->padded_average() > _avg_major_pause->padded_average()) {
    -    adjust_eden_for_minor_pause_time(is_full_gc, desired_eden_size_ptr);
    +    adjust_eden_for_minor_pause_time(desired_eden_size_ptr);
       }
       log_trace(gc, ergo)(
         "PSAdaptiveSizePolicy::adjust_eden_for_pause_time "
    @@ -880,17 +873,6 @@ size_t PSAdaptiveSizePolicy::scale_down(size_t change,
       return reduced_change;
     }
     
    -size_t PSAdaptiveSizePolicy::eden_increment(size_t cur_eden,
    -                                            uint percent_change) {
    -  size_t eden_heap_delta;
    -  eden_heap_delta = cur_eden / 100 * percent_change;
    -  return eden_heap_delta;
    -}
    -
    -size_t PSAdaptiveSizePolicy::eden_increment(size_t cur_eden) {
    -  return eden_increment(cur_eden, YoungGenerationSizeIncrement);
    -}
    -
     size_t PSAdaptiveSizePolicy::eden_increment_with_supplement_aligned_up(
       size_t cur_eden) {
       size_t result = eden_increment(cur_eden,
    @@ -903,23 +885,6 @@ size_t PSAdaptiveSizePolicy::eden_decrement_aligned_down(size_t cur_eden) {
       return align_down(eden_heap_delta, _space_alignment);
     }
     
    -size_t PSAdaptiveSizePolicy::eden_decrement(size_t cur_eden) {
    -  size_t eden_heap_delta = eden_increment(cur_eden) /
    -    AdaptiveSizeDecrementScaleFactor;
    -  return eden_heap_delta;
    -}
    -
    -size_t PSAdaptiveSizePolicy::promo_increment(size_t cur_promo,
    -                                             uint percent_change) {
    -  size_t promo_heap_delta;
    -  promo_heap_delta = cur_promo / 100 * percent_change;
    -  return promo_heap_delta;
    -}
    -
    -size_t PSAdaptiveSizePolicy::promo_increment(size_t cur_promo) {
    -  return promo_increment(cur_promo, TenuredGenerationSizeIncrement);
    -}
    -
     size_t PSAdaptiveSizePolicy::promo_increment_with_supplement_aligned_up(
       size_t cur_promo) {
       size_t result =  promo_increment(cur_promo,
    @@ -932,12 +897,6 @@ size_t PSAdaptiveSizePolicy::promo_decrement_aligned_down(size_t cur_promo) {
       return align_down(promo_heap_delta, _space_alignment);
     }
     
    -size_t PSAdaptiveSizePolicy::promo_decrement(size_t cur_promo) {
    -  size_t promo_heap_delta = promo_increment(cur_promo);
    -  promo_heap_delta = promo_heap_delta / AdaptiveSizeDecrementScaleFactor;
    -  return promo_heap_delta;
    -}
    -
     uint PSAdaptiveSizePolicy::compute_survivor_space_size_and_threshold(
                                                  bool is_survivor_overflow,
                                                  uint tenuring_threshold,
    diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp
    index 580ff9d06c0..f6d4be029fb 100644
    --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp
    +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp
    @@ -75,8 +75,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
       // Statistical data gathered for GC
       GCStats _gc_stats;
     
    -  const double _collection_cost_margin_fraction;
    -
       // Variable for estimating the major and minor pause times.
       // These variables represent linear least-squares fits of
       // the data.
    @@ -116,19 +114,13 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
      private:
     
       // Accessors
    -  AdaptivePaddedAverage* avg_major_pause() const { return _avg_major_pause; }
       double gc_minor_pause_goal_sec() const { return _gc_minor_pause_goal_sec; }
     
    -  void adjust_eden_for_minor_pause_time(bool is_full_gc,
    -                                   size_t* desired_eden_size_ptr);
    +  void adjust_eden_for_minor_pause_time(size_t* desired_eden_size_ptr);
       // Change the generation sizes to achieve a GC pause time goal
       // Returned sizes are not necessarily aligned.
    -  void adjust_promo_for_pause_time(bool is_full_gc,
    -                         size_t* desired_promo_size_ptr,
    -                         size_t* desired_eden_size_ptr);
    -  void adjust_eden_for_pause_time(bool is_full_gc,
    -                         size_t* desired_promo_size_ptr,
    -                         size_t* desired_eden_size_ptr);
    +  void adjust_promo_for_pause_time(size_t* desired_promo_size_ptr);
    +  void adjust_eden_for_pause_time(size_t* desired_eden_size_ptr);
       // Change the generation sizes to achieve an application throughput goal
       // Returned sizes are not necessarily aligned.
       void adjust_promo_for_throughput(bool is_full_gc,
    @@ -143,14 +135,10 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
                                        size_t desired_total);
     
       // Size in bytes for an increment or decrement of eden.
    -  virtual size_t eden_increment(size_t cur_eden, uint percent_change);
    -  virtual size_t eden_decrement(size_t cur_eden);
       size_t eden_decrement_aligned_down(size_t cur_eden);
       size_t eden_increment_with_supplement_aligned_up(size_t cur_eden);
     
       // Size in bytes for an increment or decrement of the promotion area
    -  virtual size_t promo_increment(size_t cur_promo, uint percent_change);
    -  virtual size_t promo_decrement(size_t cur_promo);
       size_t promo_decrement_aligned_down(size_t cur_promo);
       size_t promo_increment_with_supplement_aligned_up(size_t cur_promo);
     
    @@ -160,7 +148,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
       size_t scale_down(size_t change, double part, double total);
     
      protected:
    -  // Time accessors
     
       // Footprint accessors
       size_t live_space() const {
    @@ -175,9 +162,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
       void set_promo_size(size_t new_size) {
         _promo_size = new_size;
       }
    -  void set_survivor_size(size_t new_size) {
    -    _survivor_size = new_size;
    -  }
     
       // Update estimators
       void update_minor_pause_old_estimator(double minor_pause_in_ms);
    @@ -185,9 +169,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
       virtual GCPolicyKind kind() const { return _gc_ps_adaptive_size_policy; }
     
      public:
    -  virtual size_t eden_increment(size_t cur_eden);
    -  virtual size_t promo_increment(size_t cur_promo);
    -
       // Accessors for use by performance counters
       AdaptivePaddedNoZeroDevAverage*  avg_promoted() const {
         return _gc_stats.avg_promoted();
    @@ -226,10 +207,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
     
       size_t calculated_old_free_size_in_bytes() const;
     
    -  size_t average_old_live_in_bytes() const {
    -    return (size_t) avg_old_live()->average();
    -  }
    -
       size_t average_promoted_in_bytes() const {
         return (size_t)avg_promoted()->average();
       }
    @@ -252,40 +229,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
         _change_old_gen_for_min_pauses = v;
       }
     
    -  // Return true if the old generation size was changed
    -  // to try to reach a pause time goal.
    -  bool old_gen_changed_for_pauses() {
    -    bool result = _change_old_gen_for_maj_pauses != 0 ||
    -                  _change_old_gen_for_min_pauses != 0;
    -    return result;
    -  }
    -
    -  // Return true if the young generation size was changed
    -  // to try to reach a pause time goal.
    -  bool young_gen_changed_for_pauses() {
    -    bool result = _change_young_gen_for_min_pauses != 0 ||
    -                  _change_young_gen_for_maj_pauses != 0;
    -    return result;
    -  }
    -  // end flags for pause goal
    -
    -  // Return true if the old generation size was changed
    -  // to try to reach a throughput goal.
    -  bool old_gen_changed_for_throughput() {
    -    bool result = _change_old_gen_for_throughput != 0;
    -    return result;
    -  }
    -
    -  // Return true if the young generation size was changed
    -  // to try to reach a throughput goal.
    -  bool young_gen_changed_for_throughput() {
    -    bool result = _change_young_gen_for_throughput != 0;
    -    return result;
    -  }
    -
    -  int decrease_for_footprint() { return _decrease_for_footprint; }
    -
    -
       // Accessors for estimators.  The slope of the linear fit is
       // currently all that is used for making decisions.
     
    @@ -293,18 +236,12 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
         return _major_pause_old_estimator;
       }
     
    -  LinearLeastSquareFit* major_pause_young_estimator() {
    -    return _major_pause_young_estimator;
    -  }
    -
    -
       virtual void clear_generation_free_space_flags();
     
       double major_pause_old_slope() { return _major_pause_old_estimator->slope(); }
       double major_pause_young_slope() {
         return _major_pause_young_estimator->slope();
       }
    -  double major_collection_slope() { return _major_collection_estimator->slope();}
     
       // Calculates optimal (free) space sizes for both the young and old
       // generations.  Stores results in _eden_size and _promo_size.
    diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp
    index ecff82acbce..91fcf026069 100644
    --- a/src/hotspot/share/gc/parallel/psCardTable.cpp
    +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp
    @@ -111,7 +111,7 @@ void PSCardTable::scan_obj_with_limit(PSPromotionManager* pm,
       }
     }
     
    -void PSCardTable::pre_scavenge(HeapWord* old_gen_bottom, uint active_workers) {
    +void PSCardTable::pre_scavenge(uint active_workers) {
       _preprocessing_active_workers = active_workers;
     }
     
    diff --git a/src/hotspot/share/gc/parallel/psCardTable.hpp b/src/hotspot/share/gc/parallel/psCardTable.hpp
    index 3c510267bc3..70c32d23b7f 100644
    --- a/src/hotspot/share/gc/parallel/psCardTable.hpp
    +++ b/src/hotspot/share/gc/parallel/psCardTable.hpp
    @@ -73,7 +73,7 @@ class PSCardTable: public CardTable {
                                           _preprocessing_active_workers(0) {}
     
       // Scavenge support
    -  void pre_scavenge(HeapWord* old_gen_bottom, uint active_workers);
    +  void pre_scavenge(uint active_workers);
       // Scavenge contents of stripes with the given index.
       void scavenge_contents_parallel(ObjectStartArray* start_array,
                                       HeapWord* old_gen_bottom,
    diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp
    index 0774597dbfa..c0eb5460228 100644
    --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp
    +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp
    @@ -47,9 +47,9 @@ class PCMarkAndPushClosure: public OopClosure {
     public:
       PCMarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
     
    -  template  void do_oop_nv(T* p)      { _compaction_manager->mark_and_push(p); }
    -  virtual void do_oop(oop* p)                     { do_oop_nv(p); }
    -  virtual void do_oop(narrowOop* p)               { do_oop_nv(p); }
    +  template  void do_oop_work(T* p)      { _compaction_manager->mark_and_push(p); }
    +  virtual void do_oop(oop* p)                     { do_oop_work(p); }
    +  virtual void do_oop(narrowOop* p)               { do_oop_work(p); }
     };
     
     class PCIterateMarkAndPushClosure: public ClaimMetadataVisitingOopIterateClosure {
    @@ -60,9 +60,9 @@ class PCIterateMarkAndPushClosure: public ClaimMetadataVisitingOopIterateClosure
         ClaimMetadataVisitingOopIterateClosure(ClassLoaderData::_claim_stw_fullgc_mark, rp),
         _compaction_manager(cm) { }
     
    -  template  void do_oop_nv(T* p)      { _compaction_manager->mark_and_push(p); }
    -  virtual void do_oop(oop* p)                     { do_oop_nv(p); }
    -  virtual void do_oop(narrowOop* p)               { do_oop_nv(p); }
    +  template  void do_oop_work(T* p)      { _compaction_manager->mark_and_push(p); }
    +  virtual void do_oop(oop* p)                     { do_oop_work(p); }
    +  virtual void do_oop(narrowOop* p)               { do_oop_work(p); }
     };
     
     inline bool ParCompactionManager::steal(int queue_num, oop& t) {
    diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
    index edb6723bf0a..0bc10f8652f 100644
    --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp
    +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
    @@ -416,8 +416,8 @@ print_initial_summary_data(ParallelCompactData& summary_data,
     #endif  // #ifndef PRODUCT
     
     ParallelCompactData::ParallelCompactData() :
    -  _region_start(nullptr),
    -  DEBUG_ONLY(_region_end(nullptr) COMMA)
    +  _heap_start(nullptr),
    +  DEBUG_ONLY(_heap_end(nullptr) COMMA)
       _region_vspace(nullptr),
       _reserved_byte_size(0),
       _region_data(nullptr),
    @@ -426,16 +426,16 @@ ParallelCompactData::ParallelCompactData() :
       _block_data(nullptr),
       _block_count(0) {}
     
    -bool ParallelCompactData::initialize(MemRegion covered_region)
    +bool ParallelCompactData::initialize(MemRegion reserved_heap)
     {
    -  _region_start = covered_region.start();
    -  const size_t region_size = covered_region.word_size();
    -  DEBUG_ONLY(_region_end = _region_start + region_size;)
    +  _heap_start = reserved_heap.start();
    +  const size_t heap_size = reserved_heap.word_size();
    +  DEBUG_ONLY(_heap_end = _heap_start + heap_size;)
     
    -  assert(region_align_down(_region_start) == _region_start,
    +  assert(region_align_down(_heap_start) == _heap_start,
              "region start not aligned");
     
    -  bool result = initialize_region_data(region_size) && initialize_block_data();
    +  bool result = initialize_region_data(heap_size) && initialize_block_data();
       return result;
     }
     
    @@ -468,12 +468,11 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size)
       return 0;
     }
     
    -bool ParallelCompactData::initialize_region_data(size_t region_size)
    +bool ParallelCompactData::initialize_region_data(size_t heap_size)
     {
    -  assert((region_size & RegionSizeOffsetMask) == 0,
    -         "region size not a multiple of RegionSize");
    +  assert(is_aligned(heap_size, RegionSize), "precondition");
     
    -  const size_t count = region_size >> Log2RegionSize;
    +  const size_t count = heap_size >> Log2RegionSize;
       _region_vspace = create_vspace(count, sizeof(RegionData));
       if (_region_vspace != 0) {
         _region_data = (RegionData*)_region_vspace->reserved_low_addr();
    @@ -531,7 +530,7 @@ HeapWord* ParallelCompactData::partial_obj_end(size_t region_idx) const
     
     void ParallelCompactData::add_obj(HeapWord* addr, size_t len)
     {
    -  const size_t obj_ofs = pointer_delta(addr, _region_start);
    +  const size_t obj_ofs = pointer_delta(addr, _heap_start);
       const size_t beg_region = obj_ofs >> Log2RegionSize;
       // end_region is inclusive
       const size_t end_region = (obj_ofs + len - 1) >> Log2RegionSize;
    @@ -1770,6 +1769,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
         ref_processor()->start_discovery(maximum_heap_compaction);
     
         ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */,
    +                              false /* unregister_nmethods_during_purge */,
                                   false /* lock_codeblob_free_separately */);
     
         marking_phase(&_gc_tracer);
    @@ -2079,6 +2079,10 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
           // Release unloaded nmethod's memory.
           ctx->purge_nmethods();
         }
    +    {
    +      GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", &_gc_timer);
    +      ParallelScavengeHeap::heap()->prune_unlinked_nmethods();
    +    }
         {
           GCTraceTime(Debug, gc, phases) t("Free Code Blobs", gc_timer());
           ctx->free_code_blobs();
    diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
    index 4cee322a589..94995bd4f19 100644
    --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp
    +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
    @@ -123,7 +123,6 @@ class SplitInfo
     
       // The index of the split region, the size of the partial object on that
       // region and the destination of the partial object.
    -  size_t    src_region_idx() const   { return _src_region_idx; }
       size_t    partial_obj_size() const { return _partial_obj_size; }
       HeapWord* destination() const      { return _destination; }
     
    @@ -283,9 +282,6 @@ class ParallelCompactData
         // The location of the java heap data that corresponds to this region.
         inline HeapWord* data_location() const;
     
    -    // The highest address referenced by objects in this region.
    -    inline HeapWord* highest_ref() const;
    -
         // Whether this region is available to be claimed, has been claimed, or has
         // been completed.
         //
    @@ -314,7 +310,6 @@ class ParallelCompactData
     
         // These are atomic.
         inline void add_live_obj(size_t words);
    -    inline void set_highest_ref(HeapWord* addr);
         inline void decrement_destination_count();
         inline bool claim();
     
    @@ -399,7 +394,7 @@ class ParallelCompactData
     
     public:
       ParallelCompactData();
    -  bool initialize(MemRegion covered_region);
    +  bool initialize(MemRegion reserved_heap);
     
       size_t region_count() const { return _region_count; }
       size_t reserved_byte_size() const { return _reserved_byte_size; }
    @@ -443,26 +438,16 @@ class ParallelCompactData
       inline size_t     addr_to_region_idx(const HeapWord* addr) const;
       inline RegionData* addr_to_region_ptr(const HeapWord* addr) const;
       inline HeapWord*  region_to_addr(size_t region) const;
    -  inline HeapWord*  region_to_addr(size_t region, size_t offset) const;
       inline HeapWord*  region_to_addr(const RegionData* region) const;
     
       inline HeapWord*  region_align_down(HeapWord* addr) const;
       inline HeapWord*  region_align_up(HeapWord* addr) const;
       inline bool       is_region_aligned(HeapWord* addr) const;
     
    -  // Analogous to region_offset() for blocks.
    -  size_t     block_offset(const HeapWord* addr) const;
       size_t     addr_to_block_idx(const HeapWord* addr) const;
    -  size_t     addr_to_block_idx(const oop obj) const {
    -    return addr_to_block_idx(cast_from_oop(obj));
    -  }
       inline BlockData* addr_to_block_ptr(const HeapWord* addr) const;
    -  inline HeapWord*  block_to_addr(size_t block) const;
    -  inline size_t     region_to_block_idx(size_t region) const;
     
       inline HeapWord*  block_align_down(HeapWord* addr) const;
    -  inline HeapWord*  block_align_up(HeapWord* addr) const;
    -  inline bool       is_block_aligned(HeapWord* addr) const;
     
       // Return the address one past the end of the partial object.
       HeapWord* partial_obj_end(size_t region_idx) const;
    @@ -481,13 +466,12 @@ class ParallelCompactData
     
     private:
       bool initialize_block_data();
    -  bool initialize_region_data(size_t region_size);
    +  bool initialize_region_data(size_t heap_size);
       PSVirtualSpace* create_vspace(size_t count, size_t element_size);
     
    -private:
    -  HeapWord*       _region_start;
    +  HeapWord*       _heap_start;
     #ifdef  ASSERT
    -  HeapWord*       _region_end;
    +  HeapWord*       _heap_end;
     #endif  // #ifdef ASSERT
     
       PSVirtualSpace* _region_vspace;
    @@ -564,12 +548,6 @@ inline HeapWord* ParallelCompactData::RegionData::data_location() const
       NOT_DEBUG(return nullptr;)
     }
     
    -inline HeapWord* ParallelCompactData::RegionData::highest_ref() const
    -{
    -  DEBUG_ONLY(return _highest_ref;)
    -  NOT_DEBUG(return nullptr;)
    -}
    -
     inline void ParallelCompactData::RegionData::set_data_location(HeapWord* addr)
     {
       DEBUG_ONLY(_data_location = addr;)
    @@ -598,16 +576,6 @@ inline void ParallelCompactData::RegionData::add_live_obj(size_t words)
       Atomic::add(&_dc_and_los, static_cast(words));
     }
     
    -inline void ParallelCompactData::RegionData::set_highest_ref(HeapWord* addr)
    -{
    -#ifdef ASSERT
    -  HeapWord* tmp = _highest_ref;
    -  while (addr > tmp) {
    -    tmp = Atomic::cmpxchg(&_highest_ref, tmp, addr);
    -  }
    -#endif  // #ifdef ASSERT
    -}
    -
     inline bool ParallelCompactData::RegionData::claim()
     {
       const region_sz_t los = static_cast(live_obj_size());
    @@ -662,18 +630,18 @@ ParallelCompactData::block(size_t n) const {
     inline size_t
     ParallelCompactData::region_offset(const HeapWord* addr) const
     {
    -  assert(addr >= _region_start, "bad addr");
    +  assert(addr >= _heap_start, "bad addr");
       // would mistakenly return 0 for _region_end
    -  assert(addr < _region_end, "bad addr");
    +  assert(addr < _heap_end, "bad addr");
       return (size_t(addr) & RegionAddrOffsetMask) >> LogHeapWordSize;
     }
     
     inline size_t
     ParallelCompactData::addr_to_region_idx(const HeapWord* addr) const
     {
    -  assert(addr >= _region_start, "bad addr " PTR_FORMAT " _region_start " PTR_FORMAT, p2i(addr), p2i(_region_start));
    -  assert(addr <= _region_end, "bad addr " PTR_FORMAT " _region_end " PTR_FORMAT, p2i(addr), p2i(_region_end));
    -  return pointer_delta(addr, _region_start) >> Log2RegionSize;
    +  assert(addr >= _heap_start, "bad addr " PTR_FORMAT " _region_start " PTR_FORMAT, p2i(addr), p2i(_heap_start));
    +  assert(addr <= _heap_end, "bad addr " PTR_FORMAT " _region_end " PTR_FORMAT, p2i(addr), p2i(_heap_end));
    +  return pointer_delta(addr, _heap_start) >> Log2RegionSize;
     }
     
     inline ParallelCompactData::RegionData*
    @@ -686,7 +654,7 @@ inline HeapWord*
     ParallelCompactData::region_to_addr(size_t region) const
     {
       assert(region <= _region_count, "region out of range");
    -  return _region_start + (region << Log2RegionSize);
    +  return _heap_start + (region << Log2RegionSize);
     }
     
     inline HeapWord*
    @@ -696,27 +664,19 @@ ParallelCompactData::region_to_addr(const RegionData* region) const
                                           sizeof(RegionData)));
     }
     
    -inline HeapWord*
    -ParallelCompactData::region_to_addr(size_t region, size_t offset) const
    -{
    -  assert(region <= _region_count, "region out of range");
    -  assert(offset < RegionSize, "offset too big");  // This may be too strict.
    -  return region_to_addr(region) + offset;
    -}
    -
     inline HeapWord*
     ParallelCompactData::region_align_down(HeapWord* addr) const
     {
    -  assert(addr >= _region_start, "bad addr");
    -  assert(addr < _region_end + RegionSize, "bad addr");
    +  assert(addr >= _heap_start, "bad addr");
    +  assert(addr < _heap_end + RegionSize, "bad addr");
       return (HeapWord*)(size_t(addr) & RegionAddrMask);
     }
     
     inline HeapWord*
     ParallelCompactData::region_align_up(HeapWord* addr) const
     {
    -  assert(addr >= _region_start, "bad addr");
    -  assert(addr <= _region_end, "bad addr");
    +  assert(addr >= _heap_start, "bad addr");
    +  assert(addr <= _heap_end, "bad addr");
       return region_align_down(addr + RegionSizeOffsetMask);
     }
     
    @@ -726,20 +686,12 @@ ParallelCompactData::is_region_aligned(HeapWord* addr) const
       return (size_t(addr) & RegionAddrOffsetMask) == 0;
     }
     
    -inline size_t
    -ParallelCompactData::block_offset(const HeapWord* addr) const
    -{
    -  assert(addr >= _region_start, "bad addr");
    -  assert(addr <= _region_end, "bad addr");
    -  return (size_t(addr) & BlockAddrOffsetMask) >> LogHeapWordSize;
    -}
    -
     inline size_t
     ParallelCompactData::addr_to_block_idx(const HeapWord* addr) const
     {
    -  assert(addr >= _region_start, "bad addr");
    -  assert(addr <= _region_end, "bad addr");
    -  return pointer_delta(addr, _region_start) >> Log2BlockSize;
    +  assert(addr >= _heap_start, "bad addr");
    +  assert(addr <= _heap_end, "bad addr");
    +  return pointer_delta(addr, _heap_start) >> Log2BlockSize;
     }
     
     inline ParallelCompactData::BlockData*
    @@ -748,41 +700,14 @@ ParallelCompactData::addr_to_block_ptr(const HeapWord* addr) const
       return block(addr_to_block_idx(addr));
     }
     
    -inline HeapWord*
    -ParallelCompactData::block_to_addr(size_t block) const
    -{
    -  assert(block < _block_count, "block out of range");
    -  return _region_start + (block << Log2BlockSize);
    -}
    -
    -inline size_t
    -ParallelCompactData::region_to_block_idx(size_t region) const
    -{
    -  return region << Log2BlocksPerRegion;
    -}
    -
     inline HeapWord*
     ParallelCompactData::block_align_down(HeapWord* addr) const
     {
    -  assert(addr >= _region_start, "bad addr");
    -  assert(addr < _region_end + RegionSize, "bad addr");
    +  assert(addr >= _heap_start, "bad addr");
    +  assert(addr < _heap_end + RegionSize, "bad addr");
       return (HeapWord*)(size_t(addr) & BlockAddrMask);
     }
     
    -inline HeapWord*
    -ParallelCompactData::block_align_up(HeapWord* addr) const
    -{
    -  assert(addr >= _region_start, "bad addr");
    -  assert(addr <= _region_end, "bad addr");
    -  return block_align_down(addr + BlockSizeOffsetMask);
    -}
    -
    -inline bool
    -ParallelCompactData::is_block_aligned(HeapWord* addr) const
    -{
    -  return block_offset(addr) == 0;
    -}
    -
     // Abstract closure for use with ParMarkBitMap::iterate(), which will invoke the
     // do_addr() method.
     //
    @@ -1171,15 +1096,6 @@ class PSParallelCompact : AllStatic {
       static inline HeapWord*         dense_prefix(SpaceId space_id);
       static inline ObjectStartArray* start_array(SpaceId space_id);
     
    -  // Process the end of the given region range in the dense prefix.
    -  // This includes saving any object not updated.
    -  static void dense_prefix_regions_epilogue(ParCompactionManager* cm,
    -                                            size_t region_start_index,
    -                                            size_t region_end_index,
    -                                            idx_t exiting_object_offset,
    -                                            idx_t region_offset_start,
    -                                            idx_t region_offset_end);
    -
       // Update a region in the dense prefix.  For each live object
       // in the region, update it's interior references.  For each
       // dead object, fill it with deadwood. Dead space at the end
    diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp
    index ccf01ea3087..ff6052d5070 100644
    --- a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp
    +++ b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp
    @@ -130,9 +130,9 @@ class PCAdjustPointerClosure: public BasicOopIterateClosure {
     public:
       PCAdjustPointerClosure(ParCompactionManager* cm) : _cm(cm) {
       }
    -  template  void do_oop_nv(T* p) { PSParallelCompact::adjust_pointer(p, _cm); }
    -  virtual void do_oop(oop* p)                { do_oop_nv(p); }
    -  virtual void do_oop(narrowOop* p)          { do_oop_nv(p); }
    +  template  void do_oop_work(T* p) { PSParallelCompact::adjust_pointer(p, _cm); }
    +  virtual void do_oop(oop* p)                { do_oop_work(p); }
    +  virtual void do_oop(narrowOop* p)          { do_oop_work(p); }
     
       virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; }
     private:
    diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp
    index 2c52a123d2c..294f2d099ae 100644
    --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp
    +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp
    @@ -174,13 +174,9 @@ void PSPromotionManager::reset_stats() {
     #endif // TASKQUEUE_STATS
     
     PSPromotionManager::PSPromotionManager() {
    -  ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
    -
       // We set the old lab's start array.
       _old_lab.set_start_array(old_gen()->start_array());
     
    -  uint queue_size = claimed_stack_depth()->max_elems();
    -
       if (ParallelGCThreads == 1) {
         _target_stack_size = 0;
       } else {
    @@ -277,9 +273,7 @@ template  void PSPromotionManager::process_array_chunk_work(
       T* p               = base + start;
       T* const chunk_end = base + end;
       while (p < chunk_end) {
    -    if (PSScavenge::should_scavenge(p)) {
    -      claim_or_forward_depth(p);
    -    }
    +    claim_or_forward_depth(p);
         ++p;
       }
     }
    diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp
    index c1cbeb0f597..730d31893d5 100644
    --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp
    +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp
    @@ -56,11 +56,14 @@ inline void PSPromotionManager::push_depth(ScannerTask task) {
     
     template 
     inline void PSPromotionManager::claim_or_forward_depth(T* p) {
    -  assert(should_scavenge(p, true), "revisiting object?");
       assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap");
    -  oop obj = RawAccess::oop_load(p);
    -  Prefetch::write(obj->mark_addr(), 0);
    -  push_depth(ScannerTask(p));
    +  T heap_oop = RawAccess<>::oop_load(p);
    +  if (PSScavenge::is_obj_in_young(heap_oop)) {
    +    oop obj = CompressedOops::decode_not_null(heap_oop);
    +    assert(!PSScavenge::is_obj_in_to_space(obj), "revisiting object?");
    +    Prefetch::write(obj->mark_addr(), 0);
    +    push_depth(ScannerTask(p));
    +  }
     }
     
     inline void PSPromotionManager::promotion_trace_event(oop new_obj, oop old_obj,
    @@ -95,14 +98,12 @@ class PSPushContentsClosure: public BasicOopIterateClosure {
      public:
       PSPushContentsClosure(PSPromotionManager* pm) : BasicOopIterateClosure(PSScavenge::reference_processor()), _pm(pm) {}
     
    -  template  void do_oop_nv(T* p) {
    -    if (PSScavenge::should_scavenge(p)) {
    -      _pm->claim_or_forward_depth(p);
    -    }
    +  template  void do_oop_work(T* p) {
    +    _pm->claim_or_forward_depth(p);
       }
     
    -  virtual void do_oop(oop* p)       { do_oop_nv(p); }
    -  virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
    +  virtual void do_oop(oop* p)       { do_oop_work(p); }
    +  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
     };
     
     //
    diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp
    index a783dfe7155..c864ded21c5 100644
    --- a/src/hotspot/share/gc/parallel/psScavenge.cpp
    +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp
    @@ -302,7 +302,7 @@ class ScavengeRootsTask : public WorkerTask {
     
         if (!_is_old_gen_empty) {
           PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table();
    -      card_table->pre_scavenge(_old_gen->object_space()->bottom(), active_workers);
    +      card_table->pre_scavenge(active_workers);
         }
       }
     
    diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp
    index 69fa18aa0be..0c61bc9c30e 100644
    --- a/src/hotspot/share/gc/parallel/psScavenge.hpp
    +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp
    @@ -33,12 +33,10 @@
     #include "oops/oop.hpp"
     #include "utilities/stack.hpp"
     
    -class OopStack;
     class ReferenceProcessor;
     class ParallelScavengeHeap;
     class ParallelScavengeTracer;
     class PSIsAliveClosure;
    -class PSRefProcTaskExecutor;
     class STWGCTimer;
     
     class PSScavenge: AllStatic {
    diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.cpp b/src/hotspot/share/gc/parallel/psVirtualspace.cpp
    index f0ccd9a751c..a4d686d8670 100644
    --- a/src/hotspot/share/gc/parallel/psVirtualspace.cpp
    +++ b/src/hotspot/share/gc/parallel/psVirtualspace.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -113,7 +113,7 @@ void PSVirtualSpace::verify() const {
     
       // Reserved region must be non-empty or both addrs must be 0.
       assert(reserved_low_addr() < reserved_high_addr() ||
    -         reserved_low_addr() == nullptr && reserved_high_addr() == nullptr,
    +         (reserved_low_addr() == nullptr && reserved_high_addr() == nullptr),
              "bad reserved addrs");
       assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs");
     
    diff --git a/src/hotspot/share/gc/serial/cardTableRS.cpp b/src/hotspot/share/gc/serial/cardTableRS.cpp
    index 4df9fbad212..c4af2c8edb1 100644
    --- a/src/hotspot/share/gc/serial/cardTableRS.cpp
    +++ b/src/hotspot/share/gc/serial/cardTableRS.cpp
    @@ -382,20 +382,17 @@ CardTable::CardValue* CardTableRS::find_first_dirty_card(CardValue* const start_
       return end_card;
     }
     
    -// Because non-objArray objs can be imprecisely-marked (only obj-start card is
    -// dirty instead of the part containing old-to-young pointers), if the
    -// obj-start of a non-objArray is dirty, all cards that obj completely resides
    -// on are considered as dirty, since that obj will be iterated (scanned for
    -// old-to-young pointers) as a whole.
    +// Because non-objArray objs can be imprecisely marked (only the obj-start card
    +// is dirty instead of the part containing old-to-young pointers), if the
    +// obj-start of a non-objArray is dirty, all cards that the obj resides on,
    +// except the final one, are unconditionally considered as dirty. This is
    +// because that obj will be iterated (scanned for old-to-young pointers) as a
    +// whole.
     template
     CardTable::CardValue* CardTableRS::find_first_clean_card(CardValue* const start_card,
                                                              CardValue* const end_card,
                                                              CardTableRS* ct,
                                                              Func& object_start) {
    -
    -  // end_card might be just beyond the heap, so need to use the _raw variant.
    -  HeapWord* end_address = ct->addr_for_raw(end_card);
    -
       for (CardValue* current_card = start_card; current_card < end_card; /* empty */) {
         if (is_dirty(current_card)) {
           current_card++;
    @@ -418,21 +415,14 @@ CardTable::CardValue* CardTableRS::find_first_clean_card(CardValue* const start_
           return current_card;
         }
     
    -    // This might be the last object in this area, avoid trying to access the
    -    // card beyond the allowed area.
    -    HeapWord* next_address = obj_start_addr + obj->size();
    -    if (next_address >= end_address) {
    -      break;
    -    }
    -
    -    // Card occupied by next obj.
    -    CardValue* next_obj_card = ct->byte_for(next_address);
    -    if (is_clean(next_obj_card)) {
    -      return next_obj_card;
    +    // Final card occupied by obj.
    +    CardValue* obj_final_card = ct->byte_for(obj_start_addr + obj->size() - 1);
    +    if (is_clean(obj_final_card)) {
    +      return obj_final_card;
         }
     
         // Continue the search after this known-dirty card...
    -    current_card = next_obj_card + 1;
    +    current_card = obj_final_card + 1;
       }
     
       return end_card;
    diff --git a/src/hotspot/share/gc/serial/genMarkSweep.cpp b/src/hotspot/share/gc/serial/genMarkSweep.cpp
    index 0defffdb824..28ba4615f73 100644
    --- a/src/hotspot/share/gc/serial/genMarkSweep.cpp
    +++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp
    @@ -36,6 +36,7 @@
     #include "gc/serial/defNewGeneration.hpp"
     #include "gc/serial/generation.hpp"
     #include "gc/serial/genMarkSweep.hpp"
    +#include "gc/serial/markSweep.inline.hpp"
     #include "gc/serial/serialGcRefProcProxyTask.hpp"
     #include "gc/serial/serialHeap.hpp"
     #include "gc/shared/classUnloadingContext.hpp"
    @@ -48,7 +49,7 @@
     #include "gc/shared/preservedMarks.inline.hpp"
     #include "gc/shared/referencePolicy.hpp"
     #include "gc/shared/referenceProcessorPhaseTimes.hpp"
    -#include "gc/shared/space.hpp"
    +#include "gc/shared/space.inline.hpp"
     #include "gc/shared/strongRootsScope.hpp"
     #include "gc/shared/weakProcessor.hpp"
     #include "memory/universe.hpp"
    @@ -57,6 +58,7 @@
     #include "prims/jvmtiExport.hpp"
     #include "runtime/handles.inline.hpp"
     #include "runtime/javaThread.hpp"
    +#include "runtime/prefetch.inline.hpp"
     #include "runtime/synchronizer.hpp"
     #include "runtime/vmThread.hpp"
     #include "utilities/copy.hpp"
    @@ -66,98 +68,281 @@
     #include "jvmci/jvmci.hpp"
     #endif
     
    -void GenMarkSweep::invoke_at_safepoint(bool clear_all_softrefs) {
    -  assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
    +class DeadSpacer : StackObj {
    +  size_t _allowed_deadspace_words;
    +  bool _active;
    +  ContiguousSpace* _space;
     
    -  SerialHeap* gch = SerialHeap::heap();
    -#ifdef ASSERT
    -  if (gch->soft_ref_policy()->should_clear_all_soft_refs()) {
    -    assert(clear_all_softrefs, "Policy should have been checked earlier");
    +public:
    +  DeadSpacer(ContiguousSpace* space) : _allowed_deadspace_words(0), _space(space) {
    +    size_t ratio = _space->allowed_dead_ratio();
    +    _active = ratio > 0;
    +
    +    if (_active) {
    +      // We allow some amount of garbage towards the bottom of the space, so
    +      // we don't start compacting before there is a significant gain to be made.
    +      // Occasionally, we want to ensure a full compaction, which is determined
    +      // by the MarkSweepAlwaysCompactCount parameter.
    +      if ((MarkSweep::total_invocations() % MarkSweepAlwaysCompactCount) != 0) {
    +        _allowed_deadspace_words = (space->capacity() * ratio / 100) / HeapWordSize;
    +      } else {
    +        _active = false;
    +      }
    +    }
       }
    -#endif
     
    -  gch->trace_heap_before_gc(_gc_tracer);
    -
    -  // Increment the invocation count
    -  _total_invocations++;
    +  bool insert_deadspace(HeapWord* dead_start, HeapWord* dead_end) {
    +    if (!_active) {
    +      return false;
    +    }
     
    -  // Capture used regions for each generation that will be
    -  // subject to collection, so that card table adjustments can
    -  // be made intelligently (see clear / invalidate further below).
    -  gch->save_used_regions();
    +    size_t dead_length = pointer_delta(dead_end, dead_start);
    +    if (_allowed_deadspace_words >= dead_length) {
    +      _allowed_deadspace_words -= dead_length;
    +      CollectedHeap::fill_with_object(dead_start, dead_length);
    +      oop obj = cast_to_oop(dead_start);
    +      // obj->set_mark(obj->mark().set_marked());
    +
    +      assert(dead_length == obj->size(), "bad filler object size");
    +      log_develop_trace(gc, compaction)("Inserting object to dead space: " PTR_FORMAT ", " PTR_FORMAT ", " SIZE_FORMAT "b",
    +                                        p2i(dead_start), p2i(dead_end), dead_length * HeapWordSize);
    +
    +      return true;
    +    } else {
    +      _active = false;
    +      return false;
    +    }
    +  }
    +};
     
    -  allocate_stacks();
    +// Implement the "compaction" part of the mark-compact GC algorithm.
    +class Compacter {
    +  // There are four spaces in total, but only the first three can be used after
    +  // compact. IOW, old and eden/from must be enough for all live objs
    +  static constexpr uint max_num_spaces = 4;
    +
    +  struct CompactionSpace {
    +    ContiguousSpace* _space;
    +    // Will be the new top after compaction is complete.
    +    HeapWord* _compaction_top;
    +    // The first dead word in this contiguous space. It's an optimization to
    +    // skip large chunk of live objects at the beginning.
    +    HeapWord* _first_dead;
    +
    +    void init(ContiguousSpace* space) {
    +      _space = space;
    +      _compaction_top = space->bottom();
    +      _first_dead = nullptr;
    +    }
    +  };
     
    -  mark_sweep_phase1(clear_all_softrefs);
    +  CompactionSpace _spaces[max_num_spaces];
    +  // The num of spaces to be compacted, i.e. containing live objs.
    +  uint _num_spaces;
     
    -  mark_sweep_phase2();
    +  uint _index;
     
    -  // Don't add any more derived pointers during phase3
    -#if COMPILER2_OR_JVMCI
    -  assert(DerivedPointerTable::is_active(), "Sanity");
    -  DerivedPointerTable::set_active(false);
    -#endif
    +  HeapWord* get_compaction_top(uint index) const {
    +    return _spaces[index]._compaction_top;
    +  }
     
    -  mark_sweep_phase3();
    +  HeapWord* get_first_dead(uint index) const {
    +    return _spaces[index]._first_dead;
    +  }
     
    -  mark_sweep_phase4();
    +  ContiguousSpace* get_space(uint index) const {
    +    return _spaces[index]._space;
    +  }
     
    -  restore_marks();
    +  void record_first_dead(uint index, HeapWord* first_dead) {
    +    assert(_spaces[index]._first_dead == nullptr, "should write only once");
    +    _spaces[index]._first_dead = first_dead;
    +  }
     
    -  // Set saved marks for allocation profiler (and other things? -- dld)
    -  // (Should this be in general part?)
    -  gch->save_marks();
    +  HeapWord* alloc(size_t words) {
    +    while (true) {
    +      if (words <= pointer_delta(_spaces[_index]._space->end(),
    +                                 _spaces[_index]._compaction_top)) {
    +        HeapWord* result = _spaces[_index]._compaction_top;
    +        _spaces[_index]._compaction_top += words;
    +        if (_index == 0) {
    +          // old-gen requires BOT update
    +          static_cast(_spaces[0]._space)->update_for_block(result, result + words);
    +        }
    +        return result;
    +      }
    +
    +      // out-of-memory in this space
    +      _index++;
    +      assert(_index < max_num_spaces - 1, "the last space should not be used");
    +    }
    +  }
     
    -  deallocate_stacks();
    +  static void prefetch_read_scan(void* p) {
    +    if (PrefetchScanIntervalInBytes >= 0) {
    +      Prefetch::read(p, PrefetchScanIntervalInBytes);
    +    }
    +  }
     
    -  MarkSweep::_string_dedup_requests->flush();
    +  static void prefetch_write_scan(void* p) {
    +    if (PrefetchScanIntervalInBytes >= 0) {
    +      Prefetch::write(p, PrefetchScanIntervalInBytes);
    +    }
    +  }
     
    -  bool is_young_gen_empty = (gch->young_gen()->used() == 0);
    -  gch->rem_set()->maintain_old_to_young_invariant(gch->old_gen(), is_young_gen_empty);
    +  static void prefetch_write_copy(void* p) {
    +    if (PrefetchCopyIntervalInBytes >= 0) {
    +      Prefetch::write(p, PrefetchCopyIntervalInBytes);
    +    }
    +  }
     
    -  gch->prune_scavengable_nmethods();
    +  static void forward_obj(oop obj, HeapWord* new_addr) {
    +    prefetch_write_scan(obj);
    +    if (cast_from_oop(obj) != new_addr) {
    +      obj->forward_to(cast_to_oop(new_addr));
    +    } else {
    +      assert(obj->is_gc_marked(), "inv");
    +      // This obj will stay in-place. Fix the markword.
    +      obj->init_mark();
    +    }
    +  }
     
    -  // Update heap occupancy information which is used as
    -  // input to soft ref clearing policy at the next gc.
    -  Universe::heap()->update_capacity_and_used_at_gc();
    +  static HeapWord* find_next_live_addr(HeapWord* start, HeapWord* end) {
    +    for (HeapWord* i_addr = start; i_addr < end; /* empty */) {
    +      prefetch_read_scan(i_addr);
    +      oop obj = cast_to_oop(i_addr);
    +      if (obj->is_gc_marked()) {
    +        return i_addr;
    +      }
    +      i_addr += obj->size();
    +    }
    +    return end;
    +  };
     
    -  // Signal that we have completed a visit to all live objects.
    -  Universe::heap()->record_whole_heap_examined_timestamp();
    +  static size_t relocate(HeapWord* addr) {
    +    // Prefetch source and destination
    +    prefetch_read_scan(addr);
     
    -  gch->trace_heap_after_gc(_gc_tracer);
    -}
    +    oop obj = cast_to_oop(addr);
    +    oop new_obj = obj->forwardee();
    +    HeapWord* new_addr = cast_from_oop(new_obj);
    +    assert(addr != new_addr, "inv");
    +    prefetch_write_copy(new_addr);
     
    -void GenMarkSweep::allocate_stacks() {
    -  void* scratch = nullptr;
    -  size_t num_words;
    -  DefNewGeneration* young_gen = (DefNewGeneration*)SerialHeap::heap()->young_gen();
    -  young_gen->contribute_scratch(scratch, num_words);
    +    size_t obj_size = obj->size();
    +    Copy::aligned_conjoint_words(addr, new_addr, obj_size);
    +    new_obj->init_mark();
     
    -  if (scratch != nullptr) {
    -    _preserved_count_max = num_words * HeapWordSize / sizeof(PreservedMark);
    -  } else {
    -    _preserved_count_max = 0;
    +    return obj_size;
       }
     
    -  _preserved_marks = (PreservedMark*)scratch;
    -  _preserved_count = 0;
    -
    -  _preserved_overflow_stack_set.init(1);
    -}
    +public:
    +  explicit Compacter(SerialHeap* heap) {
    +    // In this order so that heap is compacted towards old-gen.
    +    _spaces[0].init(heap->old_gen()->space());
    +    _spaces[1].init(heap->young_gen()->eden());
    +    _spaces[2].init(heap->young_gen()->from());
    +
    +    bool is_promotion_failed = (heap->young_gen()->from()->next_compaction_space() != nullptr);
    +    if (is_promotion_failed) {
    +      _spaces[3].init(heap->young_gen()->to());
    +      _num_spaces = 4;
    +    } else {
    +      _num_spaces = 3;
    +    }
    +    _index = 0;
    +  }
     
    +  void phase2_calculate_new_addr() {
    +    for (uint i = 0; i < _num_spaces; ++i) {
    +      ContiguousSpace* space = get_space(i);
    +      HeapWord* cur_addr = space->bottom();
    +      HeapWord* top = space->top();
    +
    +      bool record_first_dead_done = false;
    +
    +      DeadSpacer dead_spacer(space);
    +
    +      while (cur_addr < top) {
    +        oop obj = cast_to_oop(cur_addr);
    +        size_t obj_size = obj->size();
    +        if (obj->is_gc_marked()) {
    +          HeapWord* new_addr = alloc(obj_size);
    +          forward_obj(obj, new_addr);
    +          cur_addr += obj_size;
    +        } else {
    +          // Skipping the current known-unmarked obj
    +          HeapWord* next_live_addr = find_next_live_addr(cur_addr + obj_size, top);
    +          if (dead_spacer.insert_deadspace(cur_addr, next_live_addr)) {
    +            // Register space for the filler obj
    +            alloc(pointer_delta(next_live_addr, cur_addr));
    +          } else {
    +            if (!record_first_dead_done) {
    +              record_first_dead(i, cur_addr);
    +              record_first_dead_done = true;
    +            }
    +            *(HeapWord**)cur_addr = next_live_addr;
    +          }
    +          cur_addr = next_live_addr;
    +        }
    +      }
    +
    +      if (!record_first_dead_done) {
    +        record_first_dead(i, top);
    +      }
    +    }
    +  }
     
    -void GenMarkSweep::deallocate_stacks() {
    -  if (_preserved_count_max != 0) {
    -    DefNewGeneration* young_gen = (DefNewGeneration*)SerialHeap::heap()->young_gen();
    -    young_gen->reset_scratch();
    +  void phase3_adjust_pointers() {
    +    for (uint i = 0; i < _num_spaces; ++i) {
    +      ContiguousSpace* space = get_space(i);
    +      HeapWord* cur_addr = space->bottom();
    +      HeapWord* const top = space->top();
    +      HeapWord* const first_dead = get_first_dead(i);
    +
    +      while (cur_addr < top) {
    +        prefetch_write_scan(cur_addr);
    +        if (cur_addr < first_dead || cast_to_oop(cur_addr)->is_gc_marked()) {
    +          size_t size = MarkSweep::adjust_pointers(cast_to_oop(cur_addr));
    +          cur_addr += size;
    +        } else {
    +          assert(*(HeapWord**)cur_addr > cur_addr, "forward progress");
    +          cur_addr = *(HeapWord**)cur_addr;
    +        }
    +      }
    +    }
       }
     
    -  _preserved_overflow_stack_set.reclaim();
    -  _marking_stack.clear();
    -  _objarray_stack.clear(true);
    -}
    +  void phase4_compact() {
    +    for (uint i = 0; i < _num_spaces; ++i) {
    +      ContiguousSpace* space = get_space(i);
    +      HeapWord* cur_addr = space->bottom();
    +      HeapWord* top = space->top();
    +
    +      // Check if the first obj inside this space is forwarded.
    +      if (!cast_to_oop(cur_addr)->is_forwarded()) {
    +        // Jump over consecutive (in-place) live-objs-chunk
    +        cur_addr = get_first_dead(i);
    +      }
    +
    +      while (cur_addr < top) {
    +        if (!cast_to_oop(cur_addr)->is_forwarded()) {
    +          cur_addr = *(HeapWord**) cur_addr;
    +          continue;
    +        }
    +        cur_addr += relocate(cur_addr);
    +      }
    +
    +      // Reset top and unused memory
    +      space->set_top(get_compaction_top(i));
    +      if (ZapUnusedHeapArea) {
    +        space->mangle_unused_area();
    +      }
    +    }
    +  }
    +};
     
    -void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
    +void GenMarkSweep::phase1_mark(bool clear_all_softrefs) {
       // Recursively traverse all live objects and mark them
       GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", _gc_timer);
     
    @@ -219,6 +404,10 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
           // Release unloaded nmethod's memory.
           ctx->purge_nmethods();
         }
    +    {
    +      GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", gc_timer());
    +      gch->prune_unlinked_nmethods();
    +    }
         {
           GCTraceTime(Debug, gc, phases) t("Free Code Blobs", gc_timer());
           ctx->free_code_blobs();
    @@ -237,54 +426,121 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
       }
     }
     
    +void GenMarkSweep::invoke_at_safepoint(bool clear_all_softrefs) {
    +  assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
     
    -void GenMarkSweep::mark_sweep_phase2() {
    -  // Now all live objects are marked, compute the new object addresses.
    -  GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", _gc_timer);
    +  SerialHeap* gch = SerialHeap::heap();
    +#ifdef ASSERT
    +  if (gch->soft_ref_policy()->should_clear_all_soft_refs()) {
    +    assert(clear_all_softrefs, "Policy should have been checked earlier");
    +  }
    +#endif
     
    -  SerialHeap::heap()->prepare_for_compaction();
    -}
    +  gch->trace_heap_before_gc(_gc_tracer);
     
    -class GenAdjustPointersClosure: public SerialHeap::GenClosure {
    -public:
    -  void do_generation(Generation* gen) {
    -    gen->adjust_pointers();
    +  // Increment the invocation count
    +  _total_invocations++;
    +
    +  // Capture used regions for each generation that will be
    +  // subject to collection, so that card table adjustments can
    +  // be made intelligently (see clear / invalidate further below).
    +  gch->save_used_regions();
    +
    +  allocate_stacks();
    +
    +  phase1_mark(clear_all_softrefs);
    +
    +  Compacter compacter{gch};
    +
    +  {
    +    // Now all live objects are marked, compute the new object addresses.
    +    GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", _gc_timer);
    +
    +    compacter.phase2_calculate_new_addr();
       }
    -};
     
    -void GenMarkSweep::mark_sweep_phase3() {
    -  SerialHeap* gch = SerialHeap::heap();
    +  // Don't add any more derived pointers during phase3
    +#if COMPILER2_OR_JVMCI
    +  assert(DerivedPointerTable::is_active(), "Sanity");
    +  DerivedPointerTable::set_active(false);
    +#endif
    +
    +  {
    +    // Adjust the pointers to reflect the new locations
    +    GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer());
    +
    +    ClassLoaderDataGraph::verify_claimed_marks_cleared(ClassLoaderData::_claim_stw_fullgc_adjust);
    +
    +    CodeBlobToOopClosure code_closure(&adjust_pointer_closure, CodeBlobToOopClosure::FixRelocations);
    +    gch->process_roots(SerialHeap::SO_AllCodeCache,
    +                       &adjust_pointer_closure,
    +                       &adjust_cld_closure,
    +                       &adjust_cld_closure,
    +                       &code_closure);
    +
    +    WeakProcessor::oops_do(&adjust_pointer_closure);
    +
    +    adjust_marks();
    +    compacter.phase3_adjust_pointers();
    +  }
    +
    +  {
    +    // All pointers are now adjusted, move objects accordingly
    +    GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer);
    +
    +    compacter.phase4_compact();
    +  }
     
    -  // Adjust the pointers to reflect the new locations
    -  GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer());
    +  restore_marks();
    +
    +  // Set saved marks for allocation profiler (and other things? -- dld)
    +  // (Should this be in general part?)
    +  gch->save_marks();
    +
    +  deallocate_stacks();
     
    -  ClassLoaderDataGraph::verify_claimed_marks_cleared(ClassLoaderData::_claim_stw_fullgc_adjust);
    +  MarkSweep::_string_dedup_requests->flush();
     
    -  CodeBlobToOopClosure code_closure(&adjust_pointer_closure, CodeBlobToOopClosure::FixRelocations);
    -  gch->process_roots(SerialHeap::SO_AllCodeCache,
    -                     &adjust_pointer_closure,
    -                     &adjust_cld_closure,
    -                     &adjust_cld_closure,
    -                     &code_closure);
    +  bool is_young_gen_empty = (gch->young_gen()->used() == 0);
    +  gch->rem_set()->maintain_old_to_young_invariant(gch->old_gen(), is_young_gen_empty);
     
    -  gch->gen_process_weak_roots(&adjust_pointer_closure);
    +  gch->prune_scavengable_nmethods();
     
    -  adjust_marks();
    -  GenAdjustPointersClosure blk;
    -  gch->generation_iterate(&blk, true);
    +  // Update heap occupancy information which is used as
    +  // input to soft ref clearing policy at the next gc.
    +  Universe::heap()->update_capacity_and_used_at_gc();
    +
    +  // Signal that we have completed a visit to all live objects.
    +  Universe::heap()->record_whole_heap_examined_timestamp();
    +
    +  gch->trace_heap_after_gc(_gc_tracer);
     }
     
    -class GenCompactClosure: public SerialHeap::GenClosure {
    -public:
    -  void do_generation(Generation* gen) {
    -    gen->compact();
    +void GenMarkSweep::allocate_stacks() {
    +  void* scratch = nullptr;
    +  size_t num_words;
    +  DefNewGeneration* young_gen = (DefNewGeneration*)SerialHeap::heap()->young_gen();
    +  young_gen->contribute_scratch(scratch, num_words);
    +
    +  if (scratch != nullptr) {
    +    _preserved_count_max = num_words * HeapWordSize / sizeof(PreservedMark);
    +  } else {
    +    _preserved_count_max = 0;
       }
    -};
     
    -void GenMarkSweep::mark_sweep_phase4() {
    -  // All pointers are now adjusted, move objects accordingly
    -  GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer);
    +  _preserved_marks = (PreservedMark*)scratch;
    +  _preserved_count = 0;
    +
    +  _preserved_overflow_stack_set.init(1);
    +}
     
    -  GenCompactClosure blk;
    -  SerialHeap::heap()->generation_iterate(&blk, true);
    +void GenMarkSweep::deallocate_stacks() {
    +  if (_preserved_count_max != 0) {
    +    DefNewGeneration* young_gen = (DefNewGeneration*)SerialHeap::heap()->young_gen();
    +    young_gen->reset_scratch();
    +  }
    +
    +  _preserved_overflow_stack_set.reclaim();
    +  _marking_stack.clear();
    +  _objarray_stack.clear(true);
     }
    diff --git a/src/hotspot/share/gc/serial/genMarkSweep.hpp b/src/hotspot/share/gc/serial/genMarkSweep.hpp
    index be830318bd0..520e8010573 100644
    --- a/src/hotspot/share/gc/serial/genMarkSweep.hpp
    +++ b/src/hotspot/share/gc/serial/genMarkSweep.hpp
    @@ -32,15 +32,8 @@ class GenMarkSweep : public MarkSweep {
       static void invoke_at_safepoint(bool clear_all_softrefs);
     
      private:
    -
       // Mark live objects
    -  static void mark_sweep_phase1(bool clear_all_softrefs);
    -  // Calculate new addresses
    -  static void mark_sweep_phase2();
    -  // Update pointers
    -  static void mark_sweep_phase3();
    -  // Move objects to new positions
    -  static void mark_sweep_phase4();
    +  static void phase1_mark(bool clear_all_softrefs);
     
       // Temporary data structures for traversal and storing/restoring marks
       static void allocate_stacks();
    diff --git a/src/hotspot/share/gc/serial/generation.cpp b/src/hotspot/share/gc/serial/generation.cpp
    index aa3c804ba3c..302f8f231e7 100644
    --- a/src/hotspot/share/gc/serial/generation.cpp
    +++ b/src/hotspot/share/gc/serial/generation.cpp
    @@ -173,18 +173,6 @@ HeapWord* Generation::block_start(const void* p) const {
       return blk._start;
     }
     
    -class GenerationBlockSizeClosure : public SpaceClosure {
    - public:
    -  const HeapWord* _p;
    -  size_t size;
    -  virtual void do_space(Space* s) {
    -    if (size == 0 && s->is_in_reserved(_p)) {
    -      size = s->block_size(_p);
    -    }
    -  }
    -  GenerationBlockSizeClosure(const HeapWord* p) { _p = p; size = 0; }
    -};
    -
     class GenerationBlockIsObjClosure : public SpaceClosure {
      public:
       const HeapWord* _p;
    @@ -218,34 +206,3 @@ void Generation::object_iterate(ObjectClosure* cl) {
       GenerationObjIterateClosure blk(cl);
       space_iterate(&blk);
     }
    -
    -void Generation::prepare_for_compaction(CompactPoint* cp) {
    -  // Generic implementation, can be specialized
    -  ContiguousSpace* space = first_compaction_space();
    -  while (space != nullptr) {
    -    space->prepare_for_compaction(cp);
    -    space = space->next_compaction_space();
    -  }
    -}
    -
    -class AdjustPointersClosure: public SpaceClosure {
    - public:
    -  void do_space(Space* sp) {
    -    sp->adjust_pointers();
    -  }
    -};
    -
    -void Generation::adjust_pointers() {
    -  // Note that this is done over all spaces, not just the compactible
    -  // ones.
    -  AdjustPointersClosure blk;
    -  space_iterate(&blk, true);
    -}
    -
    -void Generation::compact() {
    -  ContiguousSpace* sp = first_compaction_space();
    -  while (sp != nullptr) {
    -    sp->compact();
    -    sp = sp->next_compaction_space();
    -  }
    -}
    diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp
    index 63eefae720b..d93c2b66df7 100644
    --- a/src/hotspot/share/gc/serial/generation.hpp
    +++ b/src/hotspot/share/gc/serial/generation.hpp
    @@ -51,7 +51,7 @@
     class DefNewGeneration;
     class GCMemoryManager;
     class ContiguousSpace;
    -class CompactPoint;
    +
     class OopClosure;
     class GCStats;
     
    @@ -286,13 +286,6 @@ class Generation: public CHeapObj {
       GCStats* gc_stats() const { return _gc_stats; }
       virtual void update_gc_stats(Generation* current_generation, bool full) {}
     
    -  // Mark sweep support phase2
    -  virtual void prepare_for_compaction(CompactPoint* cp);
    -  // Mark sweep support phase3
    -  virtual void adjust_pointers();
    -  // Mark sweep support phase4
    -  virtual void compact();
    -
       // Accessing "marks".
     
       // This function gives a generation a chance to note a point between
    diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp
    index 8f126c3129e..9361a4e5eb9 100644
    --- a/src/hotspot/share/gc/serial/serialHeap.cpp
    +++ b/src/hotspot/share/gc/serial/serialHeap.cpp
    @@ -28,6 +28,7 @@
     #include "gc/serial/tenuredGeneration.inline.hpp"
     #include "gc/shared/gcLocker.inline.hpp"
     #include "gc/shared/genMemoryPools.hpp"
    +#include "gc/shared/scavengableNMethods.hpp"
     #include "gc/shared/strongRootsScope.hpp"
     #include "gc/shared/suspendibleThreadSet.hpp"
     #include "memory/universe.hpp"
    diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp
    index 75e8bf84860..6b2a5891c64 100644
    --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp
    +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp
    @@ -70,8 +70,6 @@ class TenuredGeneration: public Generation {
       GenerationCounters* _gen_counters;
       CSpaceCounters*     _space_counters;
     
    -  // Accessing spaces
    -  TenuredSpace* space() const { return _the_space; }
     
       // Attempt to expand the generation by "bytes".  Expand by at a
       // minimum "expand_bytes".  Return true if some amount (not
    @@ -85,6 +83,8 @@ class TenuredGeneration: public Generation {
      public:
       virtual void compute_new_size();
     
    +  TenuredSpace* space() const { return _the_space; }
    +
       // Grow generation with specified size (returns false if unable to grow)
       bool grow_by(size_t bytes);
       // Grow generation to reserved size.
    diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp
    index ca5458cd49c..959fb310258 100644
    --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp
    +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp
    @@ -51,15 +51,11 @@ class AdaptiveSizePolicy : public CHeapObj {
         decrease_old_gen_for_throughput_true = -7,
         decrease_young_gen_for_througput_true = -6,
     
    -    increase_old_gen_for_min_pauses_true = -5,
    -    decrease_old_gen_for_min_pauses_true = -4,
    -    decrease_young_gen_for_maj_pauses_true = -3,
         increase_young_gen_for_min_pauses_true = -2,
         increase_old_gen_for_maj_pauses_true = -1,
     
         decrease_young_gen_for_min_pauses_true = 1,
         decrease_old_gen_for_maj_pauses_true = 2,
    -    increase_young_gen_for_maj_pauses_true = 3,
     
         increase_old_gen_for_throughput_true = 4,
         increase_young_gen_for_througput_true = 5,
    @@ -267,12 +263,12 @@ class AdaptiveSizePolicy : public CHeapObj {
         // to use minor_collection_end() in its current form.
       }
     
    -  virtual size_t eden_increment(size_t cur_eden);
    -  virtual size_t eden_increment(size_t cur_eden, uint percent_change);
    -  virtual size_t eden_decrement(size_t cur_eden);
    -  virtual size_t promo_increment(size_t cur_eden);
    -  virtual size_t promo_increment(size_t cur_eden, uint percent_change);
    -  virtual size_t promo_decrement(size_t cur_eden);
    +  size_t eden_increment(size_t cur_eden);
    +  size_t eden_increment(size_t cur_eden, uint percent_change);
    +  size_t eden_decrement(size_t cur_eden);
    +  size_t promo_increment(size_t cur_eden);
    +  size_t promo_increment(size_t cur_eden, uint percent_change);
    +  size_t promo_decrement(size_t cur_eden);
     
       virtual void clear_generation_free_space_flags();
     
    @@ -344,17 +340,11 @@ class AdaptiveSizePolicy : public CHeapObj {
       AdaptiveWeightedAverage* avg_eden_live() const { return _avg_eden_live; }
       AdaptiveWeightedAverage* avg_old_live() const { return _avg_old_live; }
     
    -  AdaptivePaddedAverage*  avg_survived() const { return _avg_survived; }
    -  AdaptivePaddedNoZeroDevAverage*  avg_pretenured() { return _avg_pretenured; }
    -
       // Methods indicating events of interest to the adaptive size policy,
       // called by GC algorithms. It is the responsibility of users of this
       // policy to call these methods at the correct times!
       virtual void minor_collection_begin();
       virtual void minor_collection_end(GCCause::Cause gc_cause);
    -  virtual LinearLeastSquareFit* minor_pause_old_estimator() const {
    -    return _minor_pause_old_estimator;
    -  }
     
       LinearLeastSquareFit* minor_pause_young_estimator() {
         return _minor_pause_young_estimator;
    @@ -404,10 +394,6 @@ class AdaptiveSizePolicy : public CHeapObj {
         _overhead_checker.set_gc_overhead_limit_exceeded(v);
       }
     
    -  bool gc_overhead_limit_near() {
    -    return _overhead_checker.gc_overhead_limit_near();
    -  }
    -
       void reset_gc_overhead_limit_count() {
         _overhead_checker.reset_gc_overhead_limit_count();
       }
    diff --git a/src/hotspot/share/gc/shared/cardTable.hpp b/src/hotspot/share/gc/shared/cardTable.hpp
    index 61858075ca5..db6f9796ac1 100644
    --- a/src/hotspot/share/gc/shared/cardTable.hpp
    +++ b/src/hotspot/share/gc/shared/cardTable.hpp
    @@ -83,14 +83,6 @@ class CardTable: public CHeapObj {
         return cards_required(_whole_heap.word_size()) - 1;
       }
     
    -  // Mapping from card marking array entry to address of first word without checks.
    -  HeapWord* addr_for_raw(const CardValue* p) const {
    -    // As _byte_map_base may be "negative" (the card table has been allocated before
    -    // the heap in memory), do not use pointer_delta() to avoid the assertion failure.
    -    size_t delta = p - _byte_map_base;
    -    return (HeapWord*) (delta << _card_shift);
    -  }
    -
     private:
       void initialize_covered_region(void* region0_start, void* region1_start);
     
    @@ -152,13 +144,16 @@ class CardTable: public CHeapObj {
         return byte_after(p);
       }
     
    -  // Mapping from card marking array entry to address of first word.
    +  // Mapping from card marking array entry to address of first word
       HeapWord* addr_for(const CardValue* p) const {
         assert(p >= _byte_map && p < _byte_map + _byte_map_size,
                "out of bounds access to card marking array. p: " PTR_FORMAT
                " _byte_map: " PTR_FORMAT " _byte_map + _byte_map_size: " PTR_FORMAT,
                p2i(p), p2i(_byte_map), p2i(_byte_map + _byte_map_size));
    -    HeapWord* result = addr_for_raw(p);
    +    // As _byte_map_base may be "negative" (the card table has been allocated before
    +    // the heap in memory), do not use pointer_delta() to avoid the assertion failure.
    +    size_t delta = p - _byte_map_base;
    +    HeapWord* result = (HeapWord*) (delta << _card_shift);
         assert(_whole_heap.contains(result),
                "Returning result = " PTR_FORMAT " out of bounds of "
                " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")",
    diff --git a/src/hotspot/share/gc/shared/classUnloadingContext.cpp b/src/hotspot/share/gc/shared/classUnloadingContext.cpp
    index f624eaa6e44..6d9674ef801 100644
    --- a/src/hotspot/share/gc/shared/classUnloadingContext.cpp
    +++ b/src/hotspot/share/gc/shared/classUnloadingContext.cpp
    @@ -32,10 +32,13 @@
     
     ClassUnloadingContext* ClassUnloadingContext::_context = nullptr;
     
    -ClassUnloadingContext::ClassUnloadingContext(uint num_workers, bool lock_codeblob_free_separately) :
    +ClassUnloadingContext::ClassUnloadingContext(uint num_workers,
    +                                             bool unregister_nmethods_during_purge,
    +                                             bool lock_codeblob_free_separately) :
       _cld_head(nullptr),
       _num_nmethod_unlink_workers(num_workers),
       _unlinked_nmethods(nullptr),
    +  _unregister_nmethods_during_purge(unregister_nmethods_during_purge),
       _lock_codeblob_free_separately(lock_codeblob_free_separately) {
     
       assert(_context == nullptr, "context already set");
    @@ -113,7 +116,7 @@ void ClassUnloadingContext::purge_nmethods() {
         NMethodSet* set = _unlinked_nmethods[i];
         for (nmethod* nm : *set) {
           freed_memory += nm->size();
    -      nm->purge(false /* free_code_cache_data */);
    +      nm->purge(false /* free_code_cache_data */, _unregister_nmethods_during_purge);
         }
       }
     
    diff --git a/src/hotspot/share/gc/shared/classUnloadingContext.hpp b/src/hotspot/share/gc/shared/classUnloadingContext.hpp
    index 42a8f764fa4..30930967d38 100644
    --- a/src/hotspot/share/gc/shared/classUnloadingContext.hpp
    +++ b/src/hotspot/share/gc/shared/classUnloadingContext.hpp
    @@ -42,6 +42,7 @@ class ClassUnloadingContext : public CHeapObj {
       using NMethodSet = GrowableArrayCHeap;
       NMethodSet** _unlinked_nmethods;
     
    +  bool _unregister_nmethods_during_purge;
       bool _lock_codeblob_free_separately;
     
     public:
    @@ -49,10 +50,14 @@ class ClassUnloadingContext : public CHeapObj {
     
       // Num_nmethod_unlink_workers configures the maximum numbers of threads unlinking
       //     nmethods.
    +  // unregister_nmethods_during_purge determines whether unloaded nmethods should
    +  //     be unregistered from the garbage collector during purge. If not, ,the caller
    +  //     is responsible to do that later.
       // lock_codeblob_free_separately determines whether freeing the code blobs takes
       //     the CodeCache_lock during the whole operation (=false) or per code blob
       //     free operation (=true).
       ClassUnloadingContext(uint num_nmethod_unlink_workers,
    +                        bool unregister_nmethods_during_purge,
                             bool lock_codeblob_free_separately);
       ~ClassUnloadingContext();
     
    diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp
    index 422fef24318..1b65ee90b5d 100644
    --- a/src/hotspot/share/gc/shared/collectedHeap.cpp
    +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp
    @@ -558,9 +558,13 @@ void CollectedHeap::record_whole_heap_examined_timestamp() {
     
     void CollectedHeap::full_gc_dump(GCTimer* timer, bool before) {
       assert(timer != nullptr, "timer is null");
    +  static uint count = 0;
       if ((HeapDumpBeforeFullGC && before) || (HeapDumpAfterFullGC && !before)) {
    -    GCTraceTime(Info, gc) tm(before ? "Heap Dump (before full gc)" : "Heap Dump (after full gc)", timer);
    -    HeapDumper::dump_heap();
    +    if (FullGCHeapDumpLimit == 0 || count < FullGCHeapDumpLimit) {
    +      GCTraceTime(Info, gc) tm(before ? "Heap Dump (before full gc)" : "Heap Dump (after full gc)", timer);
    +      HeapDumper::dump_heap();
    +      count++;
    +    }
       }
     
       LogTarget(Trace, gc, classhisto) lt;
    diff --git a/src/hotspot/share/gc/shared/freeListAllocator.hpp b/src/hotspot/share/gc/shared/freeListAllocator.hpp
    index d8ab4c4e8bc..74b896963a7 100644
    --- a/src/hotspot/share/gc/shared/freeListAllocator.hpp
    +++ b/src/hotspot/share/gc/shared/freeListAllocator.hpp
    @@ -109,10 +109,10 @@ class FreeListAllocator {
       typedef LockFreeStack Stack;
     
       FreeListConfig* _config;
    -  char _name[DEFAULT_CACHE_LINE_SIZE - sizeof(FreeListConfig*)];  // Use name as padding.
    +  char _name[DEFAULT_PADDING_SIZE - sizeof(FreeListConfig*)];  // Use name as padding.
     
     #define DECLARE_PADDED_MEMBER(Id, Type, Name) \
    -  Type Name; DEFINE_PAD_MINUS_SIZE(Id, DEFAULT_CACHE_LINE_SIZE, sizeof(Type))
    +  Type Name; DEFINE_PAD_MINUS_SIZE(Id, DEFAULT_PADDING_SIZE, sizeof(Type))
       DECLARE_PADDED_MEMBER(1, volatile size_t, _free_count);
       DECLARE_PADDED_MEMBER(2, Stack, _free_list);
       DECLARE_PADDED_MEMBER(3, volatile bool, _transfer_lock);
    diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp
    index e2b30bc615e..ae8674c84a9 100644
    --- a/src/hotspot/share/gc/shared/gc_globals.hpp
    +++ b/src/hotspot/share/gc/shared/gc_globals.hpp
    @@ -408,11 +408,6 @@
               "Allowed collection cost difference between generations")         \
               range(0, 100)                                                     \
                                                                                 \
    -  product(uint, AdaptiveSizePolicyCollectionCostMargin, 50,                 \
    -          "If collection costs are within margin, reduce both by full "     \
    -          "delta")                                                          \
    -          range(0, 100)                                                     \
    -                                                                            \
       product(uint, YoungGenerationSizeIncrement, 20,                           \
               "Adaptive size percentage change in young generation")            \
               range(0, 100)                                                     \
    diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp
    index b81ce4b7782..cf101caae38 100644
    --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp
    +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp
    @@ -524,6 +524,7 @@ void GenCollectedHeap::do_collection(bool           full,
         CodeCache::on_gc_marking_cycle_start();
     
         ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */,
    +                              false /* unregister_nmethods_during_purge */,
                                   false /* lock_codeblob_free_separately */);
     
         collect_generation(_old_gen,
    @@ -582,7 +583,11 @@ void GenCollectedHeap::verify_nmethod(nmethod* nm) {
     }
     
     void GenCollectedHeap::prune_scavengable_nmethods() {
    -  ScavengableNMethods::prune_nmethods();
    +  ScavengableNMethods::prune_nmethods_not_into_young();
    +}
    +
    +void GenCollectedHeap::prune_unlinked_nmethods() {
    +  ScavengableNMethods::prune_unlinked_nmethods();
     }
     
     HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
    @@ -708,10 +713,6 @@ void GenCollectedHeap::process_roots(ScanningOption so,
       DEBUG_ONLY(ScavengableNMethods::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable));
     }
     
    -void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) {
    -  WeakProcessor::oops_do(root_closure);
    -}
    -
     bool GenCollectedHeap::no_allocs_since_save_marks() {
       return _young_gen->no_allocs_since_save_marks() &&
              _old_gen->no_allocs_since_save_marks();
    @@ -906,15 +907,6 @@ GenCollectedHeap* GenCollectedHeap::heap() {
       return named_heap(CollectedHeap::Serial);
     }
     
    -#if INCLUDE_SERIALGC
    -void GenCollectedHeap::prepare_for_compaction() {
    -  // Start by compacting into same gen.
    -  CompactPoint cp(_old_gen);
    -  _old_gen->prepare_for_compaction(&cp);
    -  _young_gen->prepare_for_compaction(&cp);
    -}
    -#endif // INCLUDE_SERIALGC
    -
     void GenCollectedHeap::verify(VerifyOption option /* ignored */) {
       log_debug(gc, verify)("%s", _old_gen->name());
       _old_gen->verify();
    diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp
    index 0f4f95f90f7..1c1759f1422 100644
    --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp
    +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp
    @@ -182,6 +182,7 @@ class GenCollectedHeap : public CollectedHeap {
       void verify_nmethod(nmethod* nm) override;
     
       void prune_scavengable_nmethods();
    +  void prune_unlinked_nmethods();
     
       // Iteration functions.
       void object_iterate(ObjectClosure* cl) override;
    @@ -291,11 +292,6 @@ class GenCollectedHeap : public CollectedHeap {
                          CLDClosure* weak_cld_closure,
                          CodeBlobToOopClosure* code_roots);
     
    -  // Apply "root_closure" to all the weak roots of the system.
    -  // These include JNI weak roots, string table,
    -  // and referents of reachable weak refs.
    -  void gen_process_weak_roots(OopClosure* root_closure);
    -
       // Set the saved marks of generations, if that makes sense.
       // In particular, if any generation might iterate over the oops
       // in other generations, it should call this method.
    @@ -339,13 +335,6 @@ class GenCollectedHeap : public CollectedHeap {
       HeapWord* mem_allocate_work(size_t size,
                                   bool is_tlab);
     
    -#if INCLUDE_SERIALGC
    -  // For use by mark-sweep.  As implemented, mark-sweep-compact is global
    -  // in an essential way: compaction is performed across generations, by
    -  // iterating over spaces.
    -  void prepare_for_compaction();
    -#endif
    -
       // Save the tops of the spaces in all generations
       void record_gen_tops_before_GC() PRODUCT_RETURN;
     
    diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp
    index 8ac9a3fc783..6c6f83177d2 100644
    --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp
    +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp
    @@ -93,13 +93,7 @@ JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) {
     }
     
     JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) {
    -  JVMFlag::Error status = JVMFlag::SUCCESS;
    -
    -  {
    -    status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose);
    -  }
    -
    -  return status;
    +  return MinMaxPLABSizeBounds("OldPLABSize", value, verbose);
     }
     
     JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
    diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.hpp b/src/hotspot/share/gc/shared/satbMarkQueue.hpp
    index d92523d7e4f..78fe2033296 100644
    --- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp
    +++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp
    @@ -85,7 +85,7 @@ class SATBMarkQueue: public PtrQueue {
     
     class SATBMarkQueueSet: public PtrQueueSet {
     
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, 0);
       PaddedEnd _list;
       volatile size_t _count_and_process_flag;
       // These are rarely (if ever) changed, so same cache line as count.
    @@ -93,7 +93,7 @@ class SATBMarkQueueSet: public PtrQueueSet {
       size_t _buffer_enqueue_threshold;
       // SATB is only active during marking.  Enqueuing is only done when active.
       bool _all_active;
    -  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 4 * sizeof(size_t));
    +  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, 4 * sizeof(size_t));
     
       BufferNode* get_completed_buffer();
       void abandon_completed_buffers();
    diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.cpp b/src/hotspot/share/gc/shared/scavengableNMethods.cpp
    index ec9983da4a9..9f961ff4bf8 100644
    --- a/src/hotspot/share/gc/shared/scavengableNMethods.cpp
    +++ b/src/hotspot/share/gc/shared/scavengableNMethods.cpp
    @@ -59,18 +59,8 @@ void ScavengableNMethods::register_nmethod(nmethod* nm) {
     }
     
     void ScavengableNMethods::unregister_nmethod(nmethod* nm) {
    -  assert_locked_or_safepoint(CodeCache_lock);
    -
    -  if (gc_data(nm).on_list()) {
    -    nmethod* prev = nullptr;
    -    for (nmethod* cur = _head; cur != nullptr; cur = gc_data(cur).next()) {
    -      if (cur == nm) {
    -        unlist_nmethod(cur, prev);
    -        return;
    -      }
    -      prev = cur;
    -    }
    -  }
    +  // All users of this method only unregister in bulk during code unloading.
    +  ShouldNotReachHere();
     }
     
     #ifndef PRODUCT
    @@ -172,10 +162,37 @@ void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) {
       debug_only(verify_unlisted_nmethods(nullptr));
     }
     
    -void ScavengableNMethods::prune_nmethods() {
    +void ScavengableNMethods::prune_nmethods_not_into_young() {
       nmethods_do_and_prune(nullptr /* No closure */);
     }
     
    +void ScavengableNMethods::prune_unlinked_nmethods() {
    +  assert_locked_or_safepoint(CodeCache_lock);
    +
    +  debug_only(mark_on_list_nmethods());
    +
    +  nmethod* prev = nullptr;
    +  nmethod* cur = _head;
    +  while (cur != nullptr) {
    +    ScavengableNMethodsData data = gc_data(cur);
    +    debug_only(data.clear_marked());
    +    assert(data.on_list(), "else shouldn't be on this list");
    +
    +    nmethod* const next = data.next();
    +
    +    if (cur->is_unlinked()) {
    +      unlist_nmethod(cur, prev);
    +    } else {
    +      prev = cur;
    +    }
    +
    +    cur = next;
    +  }
    +
    +  // Check for stray marks.
    +  debug_only(verify_unlisted_nmethods(nullptr));
    +}
    +
     // Walk the list of methods which might contain oops to the java heap.
     void ScavengableNMethods::nmethods_do(CodeBlobToOopClosure* cl) {
       nmethods_do_and_prune(cl);
    @@ -218,8 +235,9 @@ void ScavengableNMethods::mark_on_list_nmethods() {
         nmethod* nm = iter.method();
         ScavengableNMethodsData data = gc_data(nm);
         assert(data.not_marked(), "clean state");
    -    if (data.on_list())
    +    if (data.on_list()) {
           data.set_marked();
    +    }
       }
     }
     
    @@ -230,7 +248,10 @@ void ScavengableNMethods::verify_unlisted_nmethods(CodeBlobClosure* cl) {
       while(iter.next()) {
         nmethod* nm = iter.method();
     
    -    verify_nmethod(nm);
    +    // Can not verify already unlinked nmethods as they are partially invalid already.
    +    if (!nm->is_unlinked()) {
    +      verify_nmethod(nm);
    +    }
     
         if (cl != nullptr && !gc_data(nm).on_list()) {
           cl->do_code_blob(nm);
    diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.hpp b/src/hotspot/share/gc/shared/scavengableNMethods.hpp
    index 4852e6d32fb..94d594cd529 100644
    --- a/src/hotspot/share/gc/shared/scavengableNMethods.hpp
    +++ b/src/hotspot/share/gc/shared/scavengableNMethods.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -46,8 +46,10 @@ class ScavengableNMethods : public AllStatic {
       static void unregister_nmethod(nmethod* nm);
       static void verify_nmethod(nmethod* nm);
     
    -  // Remove nmethods that no longer have scavengable oops.
    -  static void prune_nmethods();
    +  // Remove nmethods that no longer have oops into young gen.
    +  static void prune_nmethods_not_into_young();
    +  // Remvoe unlinked (dead) nmethods.
    +  static void prune_unlinked_nmethods();
     
       // Apply closure to every scavengable nmethod.
       // Remove nmethods that no longer have scavengable oops.
    diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp
    index 1c2afaa8b70..67d3ad53383 100644
    --- a/src/hotspot/share/gc/shared/space.cpp
    +++ b/src/hotspot/share/gc/shared/space.cpp
    @@ -35,19 +35,13 @@
     #include "oops/oop.inline.hpp"
     #include "runtime/atomic.hpp"
     #include "runtime/java.hpp"
    -#include "runtime/prefetch.inline.hpp"
     #include "runtime/safepoint.hpp"
     #include "utilities/align.hpp"
     #include "utilities/copy.hpp"
     #include "utilities/globalDefinitions.hpp"
     #include "utilities/macros.hpp"
    -#if INCLUDE_SERIALGC
    -#include "gc/serial/serialBlockOffsetTable.inline.hpp"
    -#include "gc/serial/defNewGeneration.hpp"
    -#endif
     
     ContiguousSpace::ContiguousSpace(): Space(),
    -  _compaction_top(nullptr),
       _next_compaction_space(nullptr),
       _top(nullptr) {
       _mangler = new GenSpaceMangler(this);
    @@ -59,8 +53,7 @@ ContiguousSpace::~ContiguousSpace() {
     
     void ContiguousSpace::initialize(MemRegion mr,
                                      bool clear_space,
    -                                 bool mangle_space)
    -{
    +                                 bool mangle_space) {
       HeapWord* bottom = mr.start();
       HeapWord* end    = mr.end();
       assert(Universe::on_page_boundary(bottom) && Universe::on_page_boundary(end),
    @@ -70,7 +63,6 @@ void ContiguousSpace::initialize(MemRegion mr,
       if (clear_space) {
         clear(mangle_space);
       }
    -  set_compaction_top(bottom);
       _next_compaction_space = nullptr;
     }
     
    @@ -80,11 +72,6 @@ void ContiguousSpace::clear(bool mangle_space) {
       if (ZapUnusedHeapArea && mangle_space) {
         mangle_unused_area();
       }
    -  _compaction_top = bottom();
    -}
    -
    -bool ContiguousSpace::is_free_block(const HeapWord* p) const {
    -  return p >= _top;
     }
     
     #ifndef PRODUCT
    @@ -115,230 +102,6 @@ void ContiguousSpace::mangle_unused_area_complete() {
     #endif  // NOT_PRODUCT
     
     
    -HeapWord* ContiguousSpace::forward(oop q, size_t size,
    -                                    CompactPoint* cp, HeapWord* compact_top) {
    -  // q is alive
    -  // First check if we should switch compaction space
    -  assert(this == cp->space, "'this' should be current compaction space.");
    -  size_t compaction_max_size = pointer_delta(end(), compact_top);
    -  while (size > compaction_max_size) {
    -    // switch to next compaction space
    -    cp->space->set_compaction_top(compact_top);
    -    cp->space = cp->space->next_compaction_space();
    -    if (cp->space == nullptr) {
    -      cp->gen = GenCollectedHeap::heap()->young_gen();
    -      assert(cp->gen != nullptr, "compaction must succeed");
    -      cp->space = cp->gen->first_compaction_space();
    -      assert(cp->space != nullptr, "generation must have a first compaction space");
    -    }
    -    compact_top = cp->space->bottom();
    -    cp->space->set_compaction_top(compact_top);
    -    compaction_max_size = pointer_delta(cp->space->end(), compact_top);
    -  }
    -
    -  // store the forwarding pointer into the mark word
    -  if (cast_from_oop(q) != compact_top) {
    -    q->forward_to(cast_to_oop(compact_top));
    -    assert(q->is_gc_marked(), "encoding the pointer should preserve the mark");
    -  } else {
    -    // if the object isn't moving we can just set the mark to the default
    -    // mark and handle it specially later on.
    -    q->init_mark();
    -    assert(!q->is_forwarded(), "should not be forwarded");
    -  }
    -
    -  compact_top += size;
    -
    -  // We need to update the offset table so that the beginnings of objects can be
    -  // found during scavenge.  Note that we are updating the offset table based on
    -  // where the object will be once the compaction phase finishes.
    -  cp->space->update_for_block(compact_top - size, compact_top);
    -  return compact_top;
    -}
    -
    -#if INCLUDE_SERIALGC
    -
    -void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) {
    -  // Compute the new addresses for the live objects and store it in the mark
    -  // Used by universe::mark_sweep_phase2()
    -
    -  // We're sure to be here before any objects are compacted into this
    -  // space, so this is a good time to initialize this:
    -  set_compaction_top(bottom());
    -
    -  if (cp->space == nullptr) {
    -    assert(cp->gen != nullptr, "need a generation");
    -    assert(cp->gen->first_compaction_space() == this, "just checking");
    -    cp->space = cp->gen->first_compaction_space();
    -    cp->space->set_compaction_top(cp->space->bottom());
    -  }
    -
    -  HeapWord* compact_top = cp->space->compaction_top(); // This is where we are currently compacting to.
    -
    -  DeadSpacer dead_spacer(this);
    -
    -  HeapWord*  end_of_live = bottom();  // One byte beyond the last byte of the last live object.
    -  HeapWord*  first_dead = nullptr; // The first dead object.
    -
    -  const intx interval = PrefetchScanIntervalInBytes;
    -
    -  HeapWord* cur_obj = bottom();
    -  HeapWord* scan_limit = top();
    -
    -  while (cur_obj < scan_limit) {
    -    if (cast_to_oop(cur_obj)->is_gc_marked()) {
    -      // prefetch beyond cur_obj
    -      Prefetch::write(cur_obj, interval);
    -      size_t size = cast_to_oop(cur_obj)->size();
    -      compact_top = cp->space->forward(cast_to_oop(cur_obj), size, cp, compact_top);
    -      cur_obj += size;
    -      end_of_live = cur_obj;
    -    } else {
    -      // run over all the contiguous dead objects
    -      HeapWord* end = cur_obj;
    -      do {
    -        // prefetch beyond end
    -        Prefetch::write(end, interval);
    -        end += cast_to_oop(end)->size();
    -      } while (end < scan_limit && !cast_to_oop(end)->is_gc_marked());
    -
    -      // see if we might want to pretend this object is alive so that
    -      // we don't have to compact quite as often.
    -      if (cur_obj == compact_top && dead_spacer.insert_deadspace(cur_obj, end)) {
    -        oop obj = cast_to_oop(cur_obj);
    -        compact_top = cp->space->forward(obj, obj->size(), cp, compact_top);
    -        end_of_live = end;
    -      } else {
    -        // otherwise, it really is a free region.
    -
    -        // cur_obj is a pointer to a dead object. Use this dead memory to store a pointer to the next live object.
    -        *(HeapWord**)cur_obj = end;
    -
    -        // see if this is the first dead region.
    -        if (first_dead == nullptr) {
    -          first_dead = cur_obj;
    -        }
    -      }
    -
    -      // move on to the next object
    -      cur_obj = end;
    -    }
    -  }
    -
    -  assert(cur_obj == scan_limit, "just checking");
    -  _end_of_live = end_of_live;
    -  if (first_dead != nullptr) {
    -    _first_dead = first_dead;
    -  } else {
    -    _first_dead = end_of_live;
    -  }
    -
    -  // save the compaction_top of the compaction space.
    -  cp->space->set_compaction_top(compact_top);
    -}
    -
    -void ContiguousSpace::adjust_pointers() {
    -  // Check first is there is any work to do.
    -  if (used() == 0) {
    -    return;   // Nothing to do.
    -  }
    -
    -  // adjust all the interior pointers to point at the new locations of objects
    -  // Used by MarkSweep::mark_sweep_phase3()
    -
    -  HeapWord* cur_obj = bottom();
    -  HeapWord* const end_of_live = _end_of_live;  // Established by prepare_for_compaction().
    -  HeapWord* const first_dead = _first_dead;    // Established by prepare_for_compaction().
    -
    -  assert(first_dead <= end_of_live, "Stands to reason, no?");
    -
    -  const intx interval = PrefetchScanIntervalInBytes;
    -
    -  debug_only(HeapWord* prev_obj = nullptr);
    -  while (cur_obj < end_of_live) {
    -    Prefetch::write(cur_obj, interval);
    -    if (cur_obj < first_dead || cast_to_oop(cur_obj)->is_gc_marked()) {
    -      // cur_obj is alive
    -      // point all the oops to the new location
    -      size_t size = MarkSweep::adjust_pointers(cast_to_oop(cur_obj));
    -      debug_only(prev_obj = cur_obj);
    -      cur_obj += size;
    -    } else {
    -      debug_only(prev_obj = cur_obj);
    -      // cur_obj is not a live object, instead it points at the next live object
    -      cur_obj = *(HeapWord**)cur_obj;
    -      assert(cur_obj > prev_obj, "we should be moving forward through memory, cur_obj: " PTR_FORMAT ", prev_obj: " PTR_FORMAT, p2i(cur_obj), p2i(prev_obj));
    -    }
    -  }
    -
    -  assert(cur_obj == end_of_live, "just checking");
    -}
    -
    -void ContiguousSpace::compact() {
    -  // Copy all live objects to their new location
    -  // Used by MarkSweep::mark_sweep_phase4()
    -
    -  verify_up_to_first_dead(this);
    -
    -  HeapWord* const start = bottom();
    -  HeapWord* const end_of_live = _end_of_live;
    -
    -  assert(_first_dead <= end_of_live, "Invariant. _first_dead: " PTR_FORMAT " <= end_of_live: " PTR_FORMAT, p2i(_first_dead), p2i(end_of_live));
    -  if (_first_dead == end_of_live && (start == end_of_live || !cast_to_oop(start)->is_gc_marked())) {
    -    // Nothing to compact. The space is either empty or all live object should be left in place.
    -    clear_empty_region(this);
    -    return;
    -  }
    -
    -  const intx scan_interval = PrefetchScanIntervalInBytes;
    -  const intx copy_interval = PrefetchCopyIntervalInBytes;
    -
    -  assert(start < end_of_live, "bottom: " PTR_FORMAT " should be < end_of_live: " PTR_FORMAT, p2i(start), p2i(end_of_live));
    -  HeapWord* cur_obj = start;
    -  if (_first_dead > cur_obj && !cast_to_oop(cur_obj)->is_gc_marked()) {
    -    // All object before _first_dead can be skipped. They should not be moved.
    -    // A pointer to the first live object is stored at the memory location for _first_dead.
    -    cur_obj = *(HeapWord**)(_first_dead);
    -  }
    -
    -  debug_only(HeapWord* prev_obj = nullptr);
    -  while (cur_obj < end_of_live) {
    -    if (!cast_to_oop(cur_obj)->is_forwarded()) {
    -      debug_only(prev_obj = cur_obj);
    -      // The first word of the dead object contains a pointer to the next live object or end of space.
    -      cur_obj = *(HeapWord**)cur_obj;
    -      assert(cur_obj > prev_obj, "we should be moving forward through memory");
    -    } else {
    -      // prefetch beyond q
    -      Prefetch::read(cur_obj, scan_interval);
    -
    -      // size and destination
    -      size_t size = cast_to_oop(cur_obj)->size();
    -      HeapWord* compaction_top = cast_from_oop(cast_to_oop(cur_obj)->forwardee());
    -
    -      // prefetch beyond compaction_top
    -      Prefetch::write(compaction_top, copy_interval);
    -
    -      // copy object and reinit its mark
    -      assert(cur_obj != compaction_top, "everything in this pass should be moving");
    -      Copy::aligned_conjoint_words(cur_obj, compaction_top, size);
    -      oop new_obj = cast_to_oop(compaction_top);
    -
    -      ContinuationGCSupport::transform_stack_chunk(new_obj);
    -
    -      new_obj->init_mark();
    -      assert(new_obj->klass() != nullptr, "should have a class");
    -
    -      debug_only(prev_obj = cur_obj);
    -      cur_obj += size;
    -    }
    -  }
    -
    -  clear_empty_region(this);
    -}
    -
    -#endif // INCLUDE_SERIALGC
    -
     void Space::print_short() const { print_short_on(tty); }
     
     void Space::print_short_on(outputStream* st) const {
    @@ -481,10 +244,6 @@ HeapWord* ContiguousSpace::par_allocate(size_t size) {
     }
     
     #if INCLUDE_SERIALGC
    -void TenuredSpace::update_for_block(HeapWord* start, HeapWord* end) {
    -  _offsets.update_for_block(start, end);
    -}
    -
     HeapWord* TenuredSpace::block_start_const(const void* addr) const {
       HeapWord* cur_block = _offsets.block_start_reaching_into_card(addr);
     
    diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp
    index 5d559f74f5e..85f870ba1e2 100644
    --- a/src/hotspot/share/gc/shared/space.hpp
    +++ b/src/hotspot/share/gc/shared/space.hpp
    @@ -51,7 +51,6 @@ class Generation;
     class ContiguousSpace;
     class CardTableRS;
     class DirtyCardToOopClosure;
    -class FilteringClosure;
     
     // A Space describes a heap area. Class Space is an abstract
     // base class.
    @@ -85,12 +84,6 @@ class Space: public CHeapObj {
     
       void set_saved_mark_word(HeapWord* p) { _saved_mark_word = p; }
     
    -  // Returns true if this object has been allocated since a
    -  // generation's "save_marks" call.
    -  bool obj_allocated_since_save_marks(const oop obj) const {
    -    return cast_from_oop(obj) >= saved_mark_word();
    -  }
    -
       // Returns a subregion of the space containing only the allocated objects in
       // the space.
       virtual MemRegion used_region() const = 0;
    @@ -134,9 +127,6 @@ class Space: public CHeapObj {
       // given address.
       bool is_in_reserved(const void* p) const { return _bottom <= p && p < _end; }
     
    -  // Returns true iff the given block is not allocated.
    -  virtual bool is_free_block(const HeapWord* p) const = 0;
    -
       // Test whether p is double-aligned
       static bool is_aligned(void* p) {
         return ::is_aligned(p, sizeof(double));
    @@ -184,29 +174,12 @@ class Space: public CHeapObj {
       // Allocation (return null if full).  Enforces mutual exclusion internally.
       virtual HeapWord* par_allocate(size_t word_size) = 0;
     
    -#if INCLUDE_SERIALGC
    -  // Mark-sweep-compact support: all spaces can update pointers to objects
    -  // moving as a part of compaction.
    -  virtual void adjust_pointers() = 0;
    -#endif
    -
       void print() const;
       virtual void print_on(outputStream* st) const;
       void print_short() const;
       void print_short_on(outputStream* st) const;
     };
     
    -// A structure to represent a point at which objects are being copied
    -// during compaction.
    -class CompactPoint : public StackObj {
    -public:
    -  Generation* gen;
    -  ContiguousSpace* space;
    -
    -  CompactPoint(Generation* g = nullptr) :
    -    gen(g), space(nullptr) {}
    -};
    -
     class GenSpaceMangler;
     
     // A space in which the free area is contiguous.  It therefore supports
    @@ -215,26 +188,13 @@ class ContiguousSpace: public Space {
       friend class VMStructs;
     
     private:
    -  HeapWord* _compaction_top;
       ContiguousSpace* _next_compaction_space;
     
    -  static inline void verify_up_to_first_dead(ContiguousSpace* space) NOT_DEBUG_RETURN;
    -
    -  static inline void clear_empty_region(ContiguousSpace* space);
    -
    - protected:
    +protected:
       HeapWord* _top;
       // A helper for mangling the unused area of the space in debug builds.
       GenSpaceMangler* _mangler;
     
    -  // Used during compaction.
    -  HeapWord* _first_dead;
    -  HeapWord* _end_of_live;
    -
    -  // This the function to invoke when an allocation of an object covering
    -  // "start" to "end" occurs to update other internal data structures.
    -  virtual void update_for_block(HeapWord* start, HeapWord* the_end) { }
    -
       GenSpaceMangler* mangler() { return _mangler; }
     
       // Allocation helpers (return null if full).
    @@ -254,23 +214,13 @@ class ContiguousSpace: public Space {
     
       // The "clear" method must be called on a region that may have
       // had allocation performed in it, but is now to be considered empty.
    -  virtual void clear(bool mangle_space);
    -
    -  // Used temporarily during a compaction phase to hold the value
    -  // top should have when compaction is complete.
    -  HeapWord* compaction_top() const { return _compaction_top;    }
    -
    -  void set_compaction_top(HeapWord* value) {
    -    assert(value == nullptr || (value >= bottom() && value <= end()),
    -      "should point inside space");
    -    _compaction_top = value;
    -  }
    +  void clear(bool mangle_space);
     
       // Returns the next space (in the current generation) to be compacted in
       // the global compaction order.  Also is used to select the next
       // space into which to compact.
     
    -  virtual ContiguousSpace* next_compaction_space() const {
    +  ContiguousSpace* next_compaction_space() const {
         return _next_compaction_space;
       }
     
    @@ -278,42 +228,10 @@ class ContiguousSpace: public Space {
         _next_compaction_space = csp;
       }
     
    -#if INCLUDE_SERIALGC
    -  // MarkSweep support phase2
    -
    -  // Start the process of compaction of the current space: compute
    -  // post-compaction addresses, and insert forwarding pointers.  The fields
    -  // "cp->gen" and "cp->compaction_space" are the generation and space into
    -  // which we are currently compacting.  This call updates "cp" as necessary,
    -  // and leaves the "compaction_top" of the final value of
    -  // "cp->compaction_space" up-to-date.  Offset tables may be updated in
    -  // this phase as if the final copy had occurred; if so, "cp->threshold"
    -  // indicates when the next such action should be taken.
    -  void prepare_for_compaction(CompactPoint* cp);
    -  // MarkSweep support phase3
    -  void adjust_pointers() override;
    -  // MarkSweep support phase4
    -  virtual void compact();
    -#endif // INCLUDE_SERIALGC
    -
       // The maximum percentage of objects that can be dead in the compacted
       // live part of a compacted space ("deadwood" support.)
       virtual size_t allowed_dead_ratio() const { return 0; };
     
    -  // "q" is an object of the given "size" that should be forwarded;
    -  // "cp" names the generation ("gen") and containing "this" (which must
    -  // also equal "cp->space").  "compact_top" is where in "this" the
    -  // next object should be forwarded to.  If there is room in "this" for
    -  // the object, insert an appropriate forwarding pointer in "q".
    -  // If not, go to the next compaction space (there must
    -  // be one, since compaction must succeed -- we go to the first space of
    -  // the previous generation if necessary, updating "cp"), reset compact_top
    -  // and then forward.  In either case, returns the new value of "compact_top".
    -  // Invokes the "update_for_block" function of the then-current compaction
    -  // space.
    -  virtual HeapWord* forward(oop q, size_t size, CompactPoint* cp,
    -                    HeapWord* compact_top);
    -
       // Accessors
       HeapWord* top() const            { return _top;    }
       void set_top(HeapWord* value)    { _top = value; }
    @@ -346,8 +264,6 @@ class ContiguousSpace: public Space {
       size_t used() const override   { return byte_size(bottom(), top()); }
       size_t free() const override   { return byte_size(top(),    end()); }
     
    -  bool is_free_block(const HeapWord* p) const override;
    -
       // In a contiguous space we have a more obvious bound on what parts
       // contain objects.
       MemRegion used_region() const override { return MemRegion(bottom(), top()); }
    @@ -359,12 +275,6 @@ class ContiguousSpace: public Space {
       // Iteration
       void object_iterate(ObjectClosure* blk) override;
     
    -  // Compaction support
    -  void reset_after_compaction() {
    -    assert(compaction_top() >= bottom() && compaction_top() <= end(), "should point inside space");
    -    set_top(compaction_top());
    -  }
    -
       // Apply "blk->do_oop" to the addresses of all reference fields in objects
       // starting with the _saved_mark_word, which was noted during a generation's
       // save_marks and is required to denote the head of an object.
    @@ -388,7 +298,6 @@ class ContiguousSpace: public Space {
     
       // Addresses for inlined allocation
       HeapWord** top_addr() { return &_top; }
    -  HeapWord** end_addr() { return &_end; }
     
       void print_on(outputStream* st) const override;
     
    @@ -419,8 +328,7 @@ class TenuredSpace: public ContiguousSpace {
       inline HeapWord* allocate(size_t word_size) override;
       inline HeapWord* par_allocate(size_t word_size) override;
     
    -  // MarkSweep support phase3
    -  void update_for_block(HeapWord* start, HeapWord* end) override;
    +  inline void update_for_block(HeapWord* start, HeapWord* end);
     
       void print_on(outputStream* st) const override;
     };
    diff --git a/src/hotspot/share/gc/shared/space.inline.hpp b/src/hotspot/share/gc/shared/space.inline.hpp
    index 9c4c2864ced..bfaf84e8fac 100644
    --- a/src/hotspot/share/gc/shared/space.inline.hpp
    +++ b/src/hotspot/share/gc/shared/space.inline.hpp
    @@ -27,17 +27,12 @@
     
     #include "gc/shared/space.hpp"
     
    -#include "gc/serial/generation.hpp"
     #include "gc/shared/collectedHeap.hpp"
     #include "gc/shared/spaceDecorator.hpp"
     #include "oops/oop.inline.hpp"
     #include "oops/oopsHierarchy.hpp"
     #include "runtime/prefetch.inline.hpp"
     #include "runtime/safepoint.hpp"
    -#if INCLUDE_SERIALGC
    -#include "gc/serial/serialBlockOffsetTable.inline.hpp"
    -#include "gc/serial/markSweep.inline.hpp"
    -#endif
     
     inline HeapWord* Space::block_start(const void* p) {
       return block_start_const(p);
    @@ -60,90 +55,8 @@ inline HeapWord* TenuredSpace::par_allocate(size_t size) {
       return res;
     }
     
    -class DeadSpacer : StackObj {
    -  size_t _allowed_deadspace_words;
    -  bool _active;
    -  ContiguousSpace* _space;
    -
    -public:
    -  DeadSpacer(ContiguousSpace* space) : _allowed_deadspace_words(0), _space(space) {
    -    size_t ratio = _space->allowed_dead_ratio();
    -    _active = ratio > 0;
    -
    -    if (_active) {
    -      assert(!UseG1GC, "G1 should not be using dead space");
    -
    -      // We allow some amount of garbage towards the bottom of the space, so
    -      // we don't start compacting before there is a significant gain to be made.
    -      // Occasionally, we want to ensure a full compaction, which is determined
    -      // by the MarkSweepAlwaysCompactCount parameter.
    -      if ((MarkSweep::total_invocations() % MarkSweepAlwaysCompactCount) != 0) {
    -        _allowed_deadspace_words = (space->capacity() * ratio / 100) / HeapWordSize;
    -      } else {
    -        _active = false;
    -      }
    -    }
    -  }
    -
    -  bool insert_deadspace(HeapWord* dead_start, HeapWord* dead_end) {
    -    if (!_active) {
    -      return false;
    -    }
    -
    -    size_t dead_length = pointer_delta(dead_end, dead_start);
    -    if (_allowed_deadspace_words >= dead_length) {
    -      _allowed_deadspace_words -= dead_length;
    -      CollectedHeap::fill_with_object(dead_start, dead_length);
    -      oop obj = cast_to_oop(dead_start);
    -      obj->set_mark(obj->mark().set_marked());
    -
    -      assert(dead_length == obj->size(), "bad filler object size");
    -      log_develop_trace(gc, compaction)("Inserting object to dead space: " PTR_FORMAT ", " PTR_FORMAT ", " SIZE_FORMAT "b",
    -          p2i(dead_start), p2i(dead_end), dead_length * HeapWordSize);
    -
    -      return true;
    -    } else {
    -      _active = false;
    -      return false;
    -    }
    -  }
    -};
    -
    -#ifdef ASSERT
    -inline void ContiguousSpace::verify_up_to_first_dead(ContiguousSpace* space) {
    -  HeapWord* cur_obj = space->bottom();
    -
    -  if (cur_obj < space->_end_of_live && space->_first_dead > cur_obj && !cast_to_oop(cur_obj)->is_gc_marked()) {
    -     // we have a chunk of the space which hasn't moved and we've reinitialized
    -     // the mark word during the previous pass, so we can't use is_gc_marked for
    -     // the traversal.
    -     HeapWord* prev_obj = nullptr;
    -
    -     while (cur_obj < space->_first_dead) {
    -       size_t size = cast_to_oop(cur_obj)->size();
    -       assert(!cast_to_oop(cur_obj)->is_gc_marked(), "should be unmarked (special dense prefix handling)");
    -       prev_obj = cur_obj;
    -       cur_obj += size;
    -     }
    -  }
    -}
    -#endif
    -
    -inline void ContiguousSpace::clear_empty_region(ContiguousSpace* space) {
    -  // Let's remember if we were empty before we did the compaction.
    -  bool was_empty = space->used_region().is_empty();
    -  // Reset space after compaction is complete
    -  space->reset_after_compaction();
    -  // We do this clear, below, since it has overloaded meanings for some
    -  // space subtypes.  For example, TenuredSpace's that were
    -  // compacted into will have had their offset table thresholds updated
    -  // continuously, but those that weren't need to have their thresholds
    -  // re-initialized.  Also mangles unused area for debugging.
    -  if (space->used_region().is_empty()) {
    -    if (!was_empty) space->clear(SpaceDecorator::Mangle);
    -  } else {
    -    if (ZapUnusedHeapArea) space->mangle_unused_area();
    -  }
    +inline void TenuredSpace::update_for_block(HeapWord* start, HeapWord* end) {
    +  _offsets.update_for_block(start, end);
     }
     #endif // INCLUDE_SERIALGC
     
    diff --git a/src/hotspot/share/gc/shared/taskTerminator.hpp b/src/hotspot/share/gc/shared/taskTerminator.hpp
    index aac4e065a5c..540d91c88bb 100644
    --- a/src/hotspot/share/gc/shared/taskTerminator.hpp
    +++ b/src/hotspot/share/gc/shared/taskTerminator.hpp
    @@ -72,9 +72,9 @@ class TaskTerminator : public CHeapObj {
       uint _n_threads;
       TaskQueueSetSuper* _queue_set;
     
    -  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
       volatile uint _offered_termination;
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile uint));
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(volatile uint));
     
       Monitor _blocker;
       Thread* _spin_master;
    diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp
    index a5e3dfdf807..2e21ba33b0b 100644
    --- a/src/hotspot/share/gc/shared/taskqueue.hpp
    +++ b/src/hotspot/share/gc/shared/taskqueue.hpp
    @@ -233,11 +233,11 @@ class TaskQueueSuper: public CHeapObj {
       }
     
     private:
    -  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
     
       // Index of the first free element after the last one pushed (mod N).
       volatile uint _bottom;
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(uint));
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(uint));
     
       // top() is the index of the oldest pushed element (mod N), and tag()
       // is the associated epoch, to distinguish different modifications of
    @@ -245,7 +245,7 @@ class TaskQueueSuper: public CHeapObj {
       // (_bottom - top()) mod N == N-1; the latter indicates underflow
       // during concurrent pop_local/pop_global.
       volatile Age _age;
    -  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(Age));
    +  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, sizeof(Age));
     
       NONCOPYABLE(TaskQueueSuper);
     
    @@ -396,7 +396,7 @@ class GenericTaskQueue: public TaskQueueSuper {
       // Element array.
       E* _elems;
     
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(E*));
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(E*));
       // Queue owner local variables. Not to be accessed by other threads.
     
       static const uint InvalidQueueId = uint(-1);
    @@ -404,7 +404,7 @@ class GenericTaskQueue: public TaskQueueSuper {
     
       int _seed; // Current random seed used for selecting a random queue during stealing.
     
    -  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(uint) + sizeof(int));
    +  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_PADDING_SIZE, sizeof(uint) + sizeof(int));
     public:
       int next_random_queue_id();
     
    diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp
    index 696cdc00dc5..a5d671a3b92 100644
    --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp
    +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp
    @@ -99,10 +99,6 @@
       nonstatic_field(CollectedHeap,               _is_gc_active,                                 bool)                                  \
       nonstatic_field(CollectedHeap,               _total_collections,                            unsigned int)                          \
                                                                                                                                          \
    -  nonstatic_field(ContiguousSpace,            _compaction_top,                               HeapWord*)                             \
    -  nonstatic_field(ContiguousSpace,            _first_dead,                                   HeapWord*)                             \
    -  nonstatic_field(ContiguousSpace,            _end_of_live,                                  HeapWord*)                             \
    -                                                                                                                                     \
       nonstatic_field(ContiguousSpace,             _top,                                          HeapWord*)                             \
       nonstatic_field(ContiguousSpace,             _saved_mark_word,                              HeapWord*)                             \
                                                                                                                                          \
    diff --git a/src/hotspot/share/gc/shared/workerPolicy.cpp b/src/hotspot/share/gc/shared/workerPolicy.cpp
    index 6db711a959e..4ab178dd6a7 100644
    --- a/src/hotspot/share/gc/shared/workerPolicy.cpp
    +++ b/src/hotspot/share/gc/shared/workerPolicy.cpp
    @@ -73,11 +73,7 @@ uint WorkerPolicy::calc_parallel_worker_threads() {
     
     uint WorkerPolicy::parallel_worker_threads() {
       if (!_parallel_worker_threads_initialized) {
    -    if (FLAG_IS_DEFAULT(ParallelGCThreads)) {
    -      _parallel_worker_threads = WorkerPolicy::calc_parallel_worker_threads();
    -    } else {
    -      _parallel_worker_threads = ParallelGCThreads;
    -    }
    +    _parallel_worker_threads = WorkerPolicy::calc_parallel_worker_threads();
         _parallel_worker_threads_initialized = true;
       }
       return _parallel_worker_threads;
    diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
    index f9ca3278a42..238f57b1538 100644
    --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
    +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
    @@ -2155,7 +2155,7 @@ void MemoryGraphFixer::collect_memory_nodes() {
               assert(m != nullptr || (c->is_Loop() && j == LoopNode::LoopBackControl && iteration == 1) || _phase->C->has_irreducible_loop() || has_never_branch(_phase->C->root()), "expect memory state");
               if (m != nullptr) {
                 if (m == prev_region && ((c->is_Loop() && j == LoopNode::LoopBackControl) || (prev_region->is_Phi() && prev_region->in(0) == c))) {
    -              assert(c->is_Loop() && j == LoopNode::LoopBackControl || _phase->C->has_irreducible_loop() || has_never_branch(_phase->C->root()), "");
    +              assert((c->is_Loop() && j == LoopNode::LoopBackControl) || _phase->C->has_irreducible_loop() || has_never_branch(_phase->C->root()), "");
                   // continue
                 } else if (unique == nullptr) {
                   unique = m;
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp
    index b2e812bb666..c36ff59d07e 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp
    @@ -357,7 +357,7 @@ void ShenandoahBarrierSet::arraycopy_work(T* src, size_t count) {
             if (EVAC && obj == fwd) {
               fwd = _heap->evacuate_object(obj, thread);
             }
    -        assert(obj != fwd || _heap->cancelled_gc(), "must be forwarded");
    +        shenandoah_assert_forwarded_except(elem_ptr, obj, _heap->cancelled_gc());
             ShenandoahHeap::atomic_update_oop(fwd, elem_ptr, o);
             obj = fwd;
           }
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetClone.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetClone.inline.hpp
    index b548073be33..13371f5e194 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetClone.inline.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetClone.inline.hpp
    @@ -53,7 +53,7 @@ class ShenandoahUpdateRefsForOopClosure: public BasicOopIterateClosure {
             if (EVAC && obj == fwd) {
               fwd = _heap->evacuate_object(obj, _thread);
             }
    -        assert(obj != fwd || _heap->cancelled_gc(), "must be forwarded");
    +        shenandoah_assert_forwarded_except(p, obj, _heap->cancelled_gc());
             ShenandoahHeap::atomic_update_oop(fwd, p, o);
             obj = fwd;
           }
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
    index 7564af5f6b7..c7284fbcead 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
    @@ -705,10 +705,8 @@ void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(oop* p) {
           if (resolved == obj) {
             resolved = _heap->evacuate_object(obj, _thread);
           }
    +      shenandoah_assert_not_in_cset_except(p, resolved, _heap->cancelled_gc());
           ShenandoahHeap::atomic_update_oop(resolved, p, obj);
    -      assert(_heap->cancelled_gc() ||
    -             _mark_context->is_marked(resolved) && !_heap->in_collection_set(resolved),
    -             "Sanity");
         }
       }
     }
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
    index d8398bb1ed8..e7cf402a527 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
    @@ -131,6 +131,27 @@ void ShenandoahDegenGC::op_degenerated() {
           // and we can do evacuation. Otherwise, it would be the shortcut cycle.
           if (heap->is_evacuation_in_progress()) {
     
    +        if (_degen_point == _degenerated_evac) {
    +          // Degeneration under oom-evac protocol allows the mutator LRB to expose
    +          // references to from-space objects. This is okay, in theory, because we
    +          // will come to the safepoint here to complete the evacuations and update
    +          // the references. However, if the from-space reference is written to a
    +          // region that was EC during final mark or was recycled after final mark
    +          // it will not have TAMS or UWM updated. Such a region is effectively
    +          // skipped during update references which can lead to crashes and corruption
    +          // if the from-space reference is accessed.
    +          if (UseTLAB) {
    +            heap->labs_make_parsable();
    +          }
    +
    +          for (size_t i = 0; i < heap->num_regions(); i++) {
    +            ShenandoahHeapRegion* r = heap->get_region(i);
    +            if (r->is_active() && r->top() > r->get_update_watermark()) {
    +              r->set_update_watermark_at_safepoint(r->top());
    +            }
    +          }
    +        }
    +
             // Degeneration under oom-evac protocol might have left some objects in
             // collection set un-evacuated. Restart evacuation from the beginning to
             // capture all objects. For all the objects that are already evacuated,
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp
    index 18fd09ead0a..4cef5378d30 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp
    @@ -910,6 +910,9 @@ class ShenandoahPostCompactClosure : public ShenandoahHeapRegionClosure {
         // Make empty regions that have been allocated into regular
         if (r->is_empty() && live > 0) {
           r->make_regular_bypass();
    +      if (ZapUnusedHeapArea) {
    +        SpaceMangler::mangle_region(MemRegion(r->top(), r->end()));
    +      }
         }
     
         // Reclaim regular regions that became empty
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
    index 67d7f0eb4fa..12eb2aad5e8 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
    @@ -504,6 +504,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) :
       _num_regions(0),
       _regions(nullptr),
       _update_refs_iterator(this),
    +  _gc_state_changed(false),
       _gc_no_progress_count(0),
       _control_thread(nullptr),
       _shenandoah_policy(policy),
    @@ -1741,27 +1742,32 @@ void ShenandoahHeap::prepare_update_heap_references(bool concurrent) {
       _update_refs_iterator.reset();
     }
     
    -void ShenandoahHeap::set_gc_state_all_threads(char state) {
    -  for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
    -    ShenandoahThreadLocalData::set_gc_state(t, state);
    +void ShenandoahHeap::propagate_gc_state_to_java_threads() {
    +  assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at Shenandoah safepoint");
    +  if (_gc_state_changed) {
    +    _gc_state_changed = false;
    +    char state = gc_state();
    +    for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
    +      ShenandoahThreadLocalData::set_gc_state(t, state);
    +    }
       }
     }
     
    -void ShenandoahHeap::set_gc_state_mask(uint mask, bool value) {
    -  assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should really be Shenandoah safepoint");
    +void ShenandoahHeap::set_gc_state(uint mask, bool value) {
    +  assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at Shenandoah safepoint");
       _gc_state.set_cond(mask, value);
    -  set_gc_state_all_threads(_gc_state.raw_value());
    +  _gc_state_changed = true;
     }
     
     void ShenandoahHeap::set_concurrent_mark_in_progress(bool in_progress) {
       assert(!has_forwarded_objects(), "Not expected before/after mark phase");
    -  set_gc_state_mask(MARKING, in_progress);
    +  set_gc_state(MARKING, in_progress);
       ShenandoahBarrierSet::satb_mark_queue_set().set_active_all_threads(in_progress, !in_progress);
     }
     
     void ShenandoahHeap::set_evacuation_in_progress(bool in_progress) {
       assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Only call this at safepoint");
    -  set_gc_state_mask(EVACUATION, in_progress);
    +  set_gc_state(EVACUATION, in_progress);
     }
     
     void ShenandoahHeap::set_concurrent_strong_root_in_progress(bool in_progress) {
    @@ -1773,7 +1779,7 @@ void ShenandoahHeap::set_concurrent_strong_root_in_progress(bool in_progress) {
     }
     
     void ShenandoahHeap::set_concurrent_weak_root_in_progress(bool cond) {
    -  set_gc_state_mask(WEAK_ROOTS, cond);
    +  set_gc_state(WEAK_ROOTS, cond);
     }
     
     GCTracer* ShenandoahHeap::tracer() {
    @@ -1822,6 +1828,7 @@ void ShenandoahHeap::stop() {
     void ShenandoahHeap::stw_unload_classes(bool full_gc) {
       if (!unload_classes()) return;
       ClassUnloadingContext ctx(_workers->active_workers(),
    +                            true /* unregister_nmethods_during_purge */,
                                 false /* lock_codeblob_free_separately */);
     
       // Unload classes and purge SystemDictionary.
    @@ -1899,7 +1906,7 @@ void ShenandoahHeap::parallel_cleaning(bool full_gc) {
     }
     
     void ShenandoahHeap::set_has_forwarded_objects(bool cond) {
    -  set_gc_state_mask(HAS_FORWARDED, cond);
    +  set_gc_state(HAS_FORWARDED, cond);
     }
     
     void ShenandoahHeap::set_unload_classes(bool uc) {
    @@ -1938,7 +1945,7 @@ void ShenandoahHeap::set_full_gc_move_in_progress(bool in_progress) {
     }
     
     void ShenandoahHeap::set_update_refs_in_progress(bool in_progress) {
    -  set_gc_state_mask(UPDATEREFS, in_progress);
    +  set_gc_state(UPDATEREFS, in_progress);
     }
     
     void ShenandoahHeap::register_nmethod(nmethod* nm) {
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
    index f5030efa748..deb0a972167 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
    @@ -124,6 +124,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo {
       friend class ShenandoahGCStateResetter;
       friend class ShenandoahParallelObjectIterator;
       friend class ShenandoahSafepoint;
    +
       // Supported GC
       friend class ShenandoahConcurrentGC;
       friend class ShenandoahDegenGC;
    @@ -283,6 +284,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo {
       };
     
     private:
    +  bool _gc_state_changed;
       ShenandoahSharedBitmap _gc_state;
       ShenandoahSharedFlag   _degenerated_gc_in_progress;
       ShenandoahSharedFlag   _full_gc_in_progress;
    @@ -291,12 +293,20 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo {
     
       size_t _gc_no_progress_count;
     
    -  void set_gc_state_all_threads(char state);
    -  void set_gc_state_mask(uint mask, bool value);
    +  // This updates the singlular, global gc state. This must happen on a safepoint.
    +  void set_gc_state(uint mask, bool value);
     
     public:
       char gc_state() const;
     
    +  // This copies the global gc state into a thread local variable for java threads.
    +  // It is primarily intended to support quick access at barriers.
    +  void propagate_gc_state_to_java_threads();
    +
    +  // This is public to support assertions that the state hasn't been changed off of
    +  // a safepoint and that any changes were propagated to java threads after the safepoint.
    +  bool has_gc_state_changed() const { return _gc_state_changed; }
    +
       void set_concurrent_mark_in_progress(bool in_progress);
       void set_evacuation_in_progress(bool in_progress);
       void set_update_refs_in_progress(bool in_progress);
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
    index f99de804bd5..f395119d46a 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
    @@ -362,7 +362,7 @@ bool ShenandoahReferenceProcessor::discover_reference(oop reference, ReferenceTy
     
       log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
       uint worker_id = WorkerThread::worker_id();
    -  _ref_proc_thread_locals->inc_encountered(type);
    +  _ref_proc_thread_locals[worker_id].inc_encountered(type);
     
       if (UseCompressedOops) {
         return discover(reference, type, worker_id);
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp
    index 422595e9313..9eec573cc56 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp
    @@ -89,6 +89,7 @@ class ShenandoahThreadLocalData {
       }
     
       static char gc_state(Thread* thread) {
    +    assert(thread->is_Java_thread(), "GC state is only synchronized to java threads");
         return data(thread)->_gc_state;
       }
     
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp
    index 81eee97f25f..bb13e9b8e22 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp
    @@ -140,6 +140,7 @@ void ShenandoahUnload::unload() {
       assert(heap->is_concurrent_weak_root_in_progress(), "Filtered by caller");
     
       ClassUnloadingContext ctx(heap->workers()->active_workers(),
    +                            true /* unregister_nmethods_during_purge */,
                                 true /* lock_codeblob_free_separately */);
     
       // Unlink stale metadata and nmethods
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp
    index 4a97e599f3e..eeeb1dcad19 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp
    @@ -35,12 +35,23 @@
     #include "interpreter/oopMapCache.hpp"
     #include "memory/universe.hpp"
     
    +bool VM_ShenandoahOperation::doit_prologue() {
    +  assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State can only be changed on a safepoint.");
    +  return true;
    +}
    +
    +void VM_ShenandoahOperation::doit_epilogue() {
    +  assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State was not synchronized to java threads.");
    +}
    +
     bool VM_ShenandoahReferenceOperation::doit_prologue() {
    +  VM_ShenandoahOperation::doit_prologue();
       Heap_lock->lock();
       return true;
     }
     
     void VM_ShenandoahReferenceOperation::doit_epilogue() {
    +  VM_ShenandoahOperation::doit_epilogue();
       OopMapCache::cleanup_old_entries();
       if (Universe::has_reference_pending_list()) {
         Heap_lock->notify_all();
    @@ -51,34 +62,41 @@ void VM_ShenandoahReferenceOperation::doit_epilogue() {
     void VM_ShenandoahInitMark::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Init Mark", SvcGCMarker::CONCURRENT);
       _gc->entry_init_mark();
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
     
     void VM_ShenandoahFinalMarkStartEvac::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Final Mark", SvcGCMarker::CONCURRENT);
       _gc->entry_final_mark();
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
     
     void VM_ShenandoahFullGC::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Full GC", SvcGCMarker::FULL);
       _full_gc->entry_full(_gc_cause);
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
     
     void VM_ShenandoahDegeneratedGC::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Degenerated GC", SvcGCMarker::CONCURRENT);
       _gc->entry_degenerated();
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
     
     void VM_ShenandoahInitUpdateRefs::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Init Update Refs", SvcGCMarker::CONCURRENT);
       _gc->entry_init_updaterefs();
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
     
     void VM_ShenandoahFinalUpdateRefs::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Final Update Refs", SvcGCMarker::CONCURRENT);
       _gc->entry_final_updaterefs();
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
     
     void VM_ShenandoahFinalRoots::doit() {
       ShenandoahGCPauseMark mark(_gc_id, "Final Roots", SvcGCMarker::CONCURRENT);
       _gc->entry_final_roots();
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
     }
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp
    index 65ddd8b1f11..1b78766935f 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp
    @@ -47,14 +47,16 @@ class VM_ShenandoahOperation : public VM_Operation {
       uint         _gc_id;
     public:
       VM_ShenandoahOperation() : _gc_id(GCId::current()) {};
    -  virtual bool skip_thread_oop_barriers() const { return true; }
    +  bool skip_thread_oop_barriers() const override { return true; }
    +  bool doit_prologue() override;
    +  void doit_epilogue() override;
     };
     
     class VM_ShenandoahReferenceOperation : public VM_ShenandoahOperation {
     public:
       VM_ShenandoahReferenceOperation() : VM_ShenandoahOperation() {};
    -  bool doit_prologue();
    -  void doit_epilogue();
    +  bool doit_prologue() override;
    +  void doit_epilogue() override;
     };
     
     class VM_ShenandoahInitMark: public VM_ShenandoahOperation {
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp
    index 1d5d962a4ec..f67cafdb8fe 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp
    @@ -620,6 +620,8 @@ void ShenandoahVerifier::verify_at_safepoint(const char *label,
       guarantee(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "only when nothing else happens");
       guarantee(ShenandoahVerify, "only when enabled, and bitmap is initialized in ShenandoahHeap::initialize");
     
    +  ShenandoahHeap::heap()->propagate_gc_state_to_java_threads();
    +
       // Avoid side-effect of changing workers' active thread count, but bypass concurrent/parallel protocol check
       ShenandoahPushWorkerScope verify_worker_scope(_heap->workers(), _heap->max_workers(), false /*bypass check*/);
     
    diff --git a/src/hotspot/share/gc/x/xHeap.cpp b/src/hotspot/share/gc/x/xHeap.cpp
    index 65da4e1c983..75d9bc08460 100644
    --- a/src/hotspot/share/gc/x/xHeap.cpp
    +++ b/src/hotspot/share/gc/x/xHeap.cpp
    @@ -249,7 +249,7 @@ void XHeap::mark_start() {
       // Enter mark phase
       XGlobalPhase = XPhaseMark;
     
    -  // Reset marking information and mark roots
    +  // Reset marking information
       _mark.start();
     
       // Update statistics
    @@ -322,6 +322,7 @@ void XHeap::process_non_strong_references() {
       _weak_roots_processor.process_weak_roots();
     
       ClassUnloadingContext ctx(_workers.active_workers(),
    +                            true /* unregister_nmethods_during_purge */,
                                 true /* lock_codeblob_free_separately */);
     
       // Unlink stale metadata and nmethods
    diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp
    index 5ebfeb75f89..192cad86e67 100644
    --- a/src/hotspot/share/gc/z/zArguments.cpp
    +++ b/src/hotspot/share/gc/z/zArguments.cpp
    @@ -143,6 +143,9 @@ void ZArguments::initialize() {
         FLAG_SET_DEFAULT(ZFragmentationLimit, 5.0);
       }
     
    +  // Set medium page size here because MaxTenuringThreshold may use it.
    +  ZHeuristics::set_medium_page_size();
    +
       if (!FLAG_IS_DEFAULT(ZTenuringThreshold) && ZTenuringThreshold != -1) {
         FLAG_SET_ERGO_IF_DEFAULT(MaxTenuringThreshold, ZTenuringThreshold);
         if (MaxTenuringThreshold == 0) {
    diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp
    index 160673e8059..a82cc67754b 100644
    --- a/src/hotspot/share/gc/z/zBarrierSet.cpp
    +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp
    @@ -152,6 +152,19 @@ void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) {
       deoptimize_allocation(thread);
     }
     
    +void ZBarrierSet::clone_obj_array(objArrayOop src_obj, objArrayOop dst_obj, size_t size) {
    +  volatile zpointer* src = (volatile zpointer*)src_obj->base();
    +  volatile zpointer* dst = (volatile zpointer*)dst_obj->base();
    +
    +  for (const zpointer* const end = cast_from_oop(src_obj) + size; src < end; src++, dst++) {
    +    zaddress elem = ZBarrier::load_barrier_on_oop_field(src);
    +    // We avoid healing here because the store below colors the pointer store good,
    +    // hence avoiding the cost of a CAS.
    +    ZBarrier::store_barrier_on_heap_oop_field(dst, false /* heal */);
    +    Atomic::store(dst, ZAddress::store_good(elem));
    +  }
    +}
    +
     void ZBarrierSet::print_on(outputStream* st) const {
       st->print_cr("ZBarrierSet");
     }
    diff --git a/src/hotspot/share/gc/z/zBarrierSet.hpp b/src/hotspot/share/gc/z/zBarrierSet.hpp
    index 3bb067daebb..9ac8535d9d7 100644
    --- a/src/hotspot/share/gc/z/zBarrierSet.hpp
    +++ b/src/hotspot/share/gc/z/zBarrierSet.hpp
    @@ -39,6 +39,8 @@ class ZBarrierSet : public BarrierSet {
       static ZBarrierSetAssembler* assembler();
       static bool barrier_needed(DecoratorSet decorators, BasicType type);
     
    +  static void clone_obj_array(objArrayOop src, objArrayOop dst, size_t size);
    +
       virtual void on_thread_create(Thread* thread);
       virtual void on_thread_destroy(Thread* thread);
       virtual void on_thread_attach(Thread* thread);
    diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp
    index 02328a2bd02..5e8cc3a8032 100644
    --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp
    +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp
    @@ -425,14 +425,13 @@ inline void ZBarrierSet::AccessBarrier::oop_arraycopy_i
       }
     }
     
    -class ZStoreBarrierOopClosure : public BasicOopIterateClosure {
    +class ZColorStoreGoodOopClosure : public BasicOopIterateClosure {
     public:
       virtual void do_oop(oop* p_) {
         volatile zpointer* const p = (volatile zpointer*)p_;
         const zpointer ptr = ZBarrier::load_atomic(p);
         const zaddress addr = ZPointer::uncolor(ptr);
    -    ZBarrier::store_barrier_on_heap_oop_field(p, false /* heal */);
    -    *p = ZAddress::store_good(addr);
    +    Atomic::store(p, ZAddress::store_good(addr));
       }
     
       virtual void do_oop(narrowOop* p) {
    @@ -455,6 +454,17 @@ template 
     inline void ZBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) {
       assert_is_valid(to_zaddress(src));
     
    +  if (dst->is_objArray()) {
    +    // Cloning an object array is similar to performing array copy.
    +    // If an array is large enough to have its allocation segmented,
    +    // this operation might require GC barriers. However, the intrinsics
    +    // for cloning arrays transform the clone to an optimized allocation
    +    // and arraycopy sequence, so the performance of this runtime call
    +    // does not matter for object arrays.
    +    clone_obj_array(objArrayOop(src), objArrayOop(dst), size);
    +    return;
    +  }
    +
       // Fix the oops
       ZLoadBarrierOopClosure cl;
       ZIterator::oop_iterate(src, &cl);
    @@ -462,10 +472,10 @@ inline void ZBarrierSet::AccessBarrier::clone_in_heap(o
       // Clone the object
       Raw::clone_in_heap(src, dst, size);
     
    -  assert(ZHeap::heap()->is_young(to_zaddress(dst)), "ZColorStoreGoodOopClosure is only valid for young objects");
    +  assert(dst->is_typeArray() || ZHeap::heap()->is_young(to_zaddress(dst)), "ZColorStoreGoodOopClosure is only valid for young objects");
     
       // Color store good before handing out
    -  ZStoreBarrierOopClosure cl_sg;
    +  ZColorStoreGoodOopClosure cl_sg;
       ZIterator::oop_iterate(dst, &cl_sg);
     }
     
    diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp
    index 4621101eb88..5e42fbd7ef8 100644
    --- a/src/hotspot/share/gc/z/zGeneration.cpp
    +++ b/src/hotspot/share/gc/z/zGeneration.cpp
    @@ -861,7 +861,7 @@ void ZGenerationYoung::mark_start() {
       // Enter mark phase
       set_phase(Phase::Mark);
     
    -  // Reset marking information and mark roots
    +  // Reset marking information
       _mark.start();
     
       // Flip remembered set bits
    @@ -1213,7 +1213,7 @@ void ZGenerationOld::mark_start() {
       // Enter mark phase
       set_phase(Phase::Mark);
     
    -  // Reset marking information and mark roots
    +  // Reset marking information
       _mark.start();
     
       // Update statistics
    @@ -1318,6 +1318,7 @@ void ZGenerationOld::process_non_strong_references() {
       _weak_roots_processor.process_weak_roots();
     
       ClassUnloadingContext ctx(_workers.active_workers(),
    +                            true /* unregister_nmethods_during_purge */,
                                 true /* lock_codeblob_free_separately */);
     
       // Unlink stale metadata and nmethods
    diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp
    index bcd9dd84405..df2f5f68489 100644
    --- a/src/hotspot/share/gc/z/zHeuristics.cpp
    +++ b/src/hotspot/share/gc/z/zHeuristics.cpp
    @@ -60,8 +60,8 @@ size_t ZHeuristics::relocation_headroom() {
     }
     
     bool ZHeuristics::use_per_cpu_shared_small_pages() {
    -  // Use per-CPU shared small pages only if these pages occupy at most 3.125%
    -  // of the max heap size. Otherwise fall back to using a single shared small
    +  // Use per-CPU shared small pages only if these pages don't have a significant
    +  // heap overhead. Otherwise fall back to using a single shared small
       // page. This is useful when using small heaps on large machines.
       const size_t per_cpu_share = significant_heap_overhead() / ZCPU::count();
       return per_cpu_share >= ZPageSizeSmall;
    diff --git a/src/hotspot/share/gc/z/zInitialize.cpp b/src/hotspot/share/gc/z/zInitialize.cpp
    index 0c0dc6e87a6..bf8cb96a4cb 100644
    --- a/src/hotspot/share/gc/z/zInitialize.cpp
    +++ b/src/hotspot/share/gc/z/zInitialize.cpp
    @@ -28,7 +28,6 @@
     #include "gc/z/zDriver.hpp"
     #include "gc/z/zGCIdPrinter.hpp"
     #include "gc/z/zGlobals.hpp"
    -#include "gc/z/zHeuristics.hpp"
     #include "gc/z/zInitialize.hpp"
     #include "gc/z/zJNICritical.hpp"
     #include "gc/z/zLargePages.hpp"
    @@ -54,7 +53,6 @@ ZInitialize::ZInitialize(ZBarrierSet* barrier_set) {
       ZThreadLocalAllocBuffer::initialize();
       ZTracer::initialize();
       ZLargePages::initialize();
    -  ZHeuristics::set_medium_page_size();
       ZBarrierSet::set_barrier_set(barrier_set);
       ZJNICritical::initialize();
       ZDriver::initialize();
    diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.cpp b/src/hotspot/share/gc/z/zReferenceProcessor.cpp
    index 1037093523d..df8cb2b0e95 100644
    --- a/src/hotspot/share/gc/z/zReferenceProcessor.cpp
    +++ b/src/hotspot/share/gc/z/zReferenceProcessor.cpp
    @@ -113,6 +113,7 @@ static void list_append(zaddress& head, zaddress& tail, zaddress reference) {
     ZReferenceProcessor::ZReferenceProcessor(ZWorkers* workers)
       : _workers(workers),
         _soft_reference_policy(nullptr),
    +    _clear_all_soft_refs(false),
         _encountered_count(),
         _discovered_count(),
         _enqueued_count(),
    @@ -124,8 +125,9 @@ void ZReferenceProcessor::set_soft_reference_policy(bool clear) {
       static AlwaysClearPolicy always_clear_policy;
       static LRUMaxHeapPolicy lru_max_heap_policy;
     
    +  _clear_all_soft_refs = clear;
    +
       if (clear) {
    -    log_info(gc, ref)("Clearing All SoftReferences");
         _soft_reference_policy = &always_clear_policy;
       } else {
         _soft_reference_policy = &lru_max_heap_policy;
    @@ -438,6 +440,10 @@ class ZReferenceProcessorTask : public ZTask {
     void ZReferenceProcessor::process_references() {
       ZStatTimerOld timer(ZSubPhaseConcurrentReferencesProcess);
     
    +  if (_clear_all_soft_refs) {
    +    log_info(gc, ref)("Clearing All SoftReferences");
    +  }
    +
       // Process discovered lists
       ZReferenceProcessorTask task(this);
       _workers->run(&task);
    diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.hpp b/src/hotspot/share/gc/z/zReferenceProcessor.hpp
    index d39cc8634cd..7a8900827da 100644
    --- a/src/hotspot/share/gc/z/zReferenceProcessor.hpp
    +++ b/src/hotspot/share/gc/z/zReferenceProcessor.hpp
    @@ -41,6 +41,7 @@ class ZReferenceProcessor : public ReferenceDiscoverer {
     
       ZWorkers* const      _workers;
       ReferencePolicy*     _soft_reference_policy;
    +  bool                 _clear_all_soft_refs;
       ZPerWorker _encountered_count;
       ZPerWorker _discovered_count;
       ZPerWorker _enqueued_count;
    diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h
    index e59db550fe9..5a58e6d57d8 100644
    --- a/src/hotspot/share/include/jvm.h
    +++ b/src/hotspot/share/include/jvm.h
    @@ -1169,6 +1169,9 @@ JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide);
     JNIEXPORT void JNICALL
     JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
     
    +JNIEXPORT void JNICALL
    +JVM_VirtualThreadDisableSuspend(JNIEnv* env, jobject vthread, jboolean enter);
    +
     /*
      * Core reflection support.
      */
    diff --git a/src/hotspot/share/interpreter/bytecodes.cpp b/src/hotspot/share/interpreter/bytecodes.cpp
    index 24c9f918a5c..0d1be1dca7b 100644
    --- a/src/hotspot/share/interpreter/bytecodes.cpp
    +++ b/src/hotspot/share/interpreter/bytecodes.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -538,7 +538,7 @@ jchar Bytecodes::compute_flags(const char* format, jchar more_flags) {
         }
         guarantee(has_size == 0 ||                     // no field yet
                   this_size == has_size ||             // same size
    -              this_size < has_size && *fp == '\0', // last field can be short
    +              (this_size < has_size && *fp == '\0'), // last field can be short
                   "mixed field sizes in format");
         has_size = this_size;
       }
    diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp
    index 45848fb0243..03b47bcd21d 100644
    --- a/src/hotspot/share/jfr/jfr.cpp
    +++ b/src/hotspot/share/jfr/jfr.cpp
    @@ -67,7 +67,9 @@ void Jfr::on_create_vm_3() {
     }
     
     void Jfr::on_unloading_classes() {
    -  JfrCheckpointManager::on_unloading_classes();
    +  if (JfrRecorder::is_created() || JfrRecorder::is_started_on_commandline()) {
    +    JfrCheckpointManager::on_unloading_classes();
    +  }
     }
     
     bool Jfr::is_excluded(Thread* t) {
    diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
    index 866f8c1df13..0b3097ca1fa 100644
    --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
    +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
    @@ -525,6 +525,12 @@ const char* JfrJavaSupport::c_str(jstring string, Thread* thread, bool c_heap /*
       return string != nullptr ? c_str(resolve_non_null(string), thread, c_heap) : nullptr;
     }
     
    +void JfrJavaSupport::free_c_str(const char* str, bool c_heap) {
    +  if (c_heap) {
    +    FREE_C_HEAP_ARRAY(char, str);
    +  }
    +}
    +
     static Symbol** allocate_symbol_array(bool c_heap, int length, Thread* thread) {
       return c_heap ?
                NEW_C_HEAP_ARRAY(Symbol*, length, mtTracing) :
    @@ -546,6 +552,7 @@ Symbol** JfrJavaSupport::symbol_array(jobjectArray string_array, JavaThread* thr
         if (object != nullptr) {
           const char* text = c_str(arrayOop->obj_at(i), thread, c_heap);
           symbol = SymbolTable::new_symbol(text);
    +      free_c_str(text, c_heap);
         }
         result_array[i] = symbol;
       }
    diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
    index 8b4ecf18dc1..19ff332c118 100644
    --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
    +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
    @@ -86,6 +86,7 @@ class JfrJavaSupport : public AllStatic {
       static Klass* klass(const jobject handle);
       static const char* c_str(jstring string, Thread* thread, bool c_heap = false);
       static const char* c_str(oop string, Thread* thread, bool c_heap = false);
    +  static void free_c_str(const char* str, bool c_heap);
       static Symbol** symbol_array(jobjectArray string_array, JavaThread* thread, intptr_t* result_size, bool c_heap = false);
     
       // exceptions
    diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml
    index c1f626a8192..53fa17555c6 100644
    --- a/src/hotspot/share/jfr/metadata/metadata.xml
    +++ b/src/hotspot/share/jfr/metadata/metadata.xml
    @@ -957,6 +957,8 @@
         
         
         
    +    
    +    
       
     
       initialize(thread_local_buffer_size,
    -                                                                        thread_local_buffer_prealloc_count,
    -                                                                        thread_local_buffer_prealloc_count)) {
    +                                                                           thread_local_buffer_prealloc_count,
    +                                                                           thread_local_buffer_prealloc_count)) {
         return false;
       }
     
       assert(_virtual_thread_local_mspace == nullptr, "invariant");
       _virtual_thread_local_mspace = new JfrThreadLocalCheckpointMspace();
       if (_virtual_thread_local_mspace == nullptr || !_virtual_thread_local_mspace->initialize(virtual_thread_local_buffer_size,
    -                                                                                        JFR_MSPACE_UNLIMITED_CACHE_SIZE,
    -                                                                                        virtual_thread_local_buffer_prealloc_count)) {
    +                                                                                           JFR_MSPACE_UNLIMITED_CACHE_SIZE,
    +                                                                                           virtual_thread_local_buffer_prealloc_count)) {
         return false;
       }
       return true;
    diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp
    index f99159b3a51..a8ec2fd70f5 100644
    --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp
    +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp
    @@ -55,6 +55,7 @@ struct JfrCheckpointContext {
     
     class JfrCheckpointWriter : public JfrCheckpointWriterBase {
       friend class JfrCheckpointManager;
    +  friend class JfrDeprecationManager;
       friend class JfrSerializerRegistration;
       friend class JfrTypeManager;
      private:
    diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp
    index 94ac0772969..8df2f6593ef 100644
    --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp
    +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp
    @@ -66,20 +66,38 @@ static bool _class_unload = false;
     static bool _flushpoint = false;
     static bool _initial_type_set = true;
     
    -static bool current_epoch() {
    -  return _class_unload || _flushpoint;
    +static inline bool flushpoint() {
    +  return _flushpoint;
     }
     
    -static bool previous_epoch() {
    +static inline bool unloading() {
    +  return _class_unload;
    +}
    +
    +static inline bool current_epoch() {
    +  return flushpoint() || unloading();
    +}
    +
    +static inline bool previous_epoch() {
       return !current_epoch();
     }
     
    -static bool is_initial_typeset_for_chunk() {
    -  return _initial_type_set && !_class_unload;
    +template 
    +static inline bool used(const T* ptr) {
    +  assert(ptr != nullptr, "invariant");
    +  return current_epoch() ? USED_THIS_EPOCH(ptr) : USED_PREVIOUS_EPOCH(ptr);
    +}
    +
    +template 
    +static inline bool not_used(const T* ptr) {
    +  return !used(ptr);
     }
     
    -static bool is_complete() {
    -  return !_artifacts->has_klass_entries() && current_epoch();
    +template 
    +static void do_artifact(const T* ptr) {
    +  if (used(ptr)) {
    +    _subsystem_callback->do_artifact(ptr);
    +  }
     }
     
     static traceid mark_symbol(KlassPtr klass, bool leakp) {
    @@ -94,66 +112,107 @@ static traceid get_bootstrap_name(bool leakp) {
       return _artifacts->bootstrap_name(leakp);
     }
     
    -static const char* primitive_name(KlassPtr type_array_klass) {
    -  switch (type_array_klass->name()->base()[1]) {
    -    case JVM_SIGNATURE_BOOLEAN: return "boolean";
    -    case JVM_SIGNATURE_BYTE: return "byte";
    -    case JVM_SIGNATURE_CHAR: return "char";
    -    case JVM_SIGNATURE_SHORT: return "short";
    -    case JVM_SIGNATURE_INT: return "int";
    -    case JVM_SIGNATURE_LONG: return "long";
    -    case JVM_SIGNATURE_FLOAT: return "float";
    -    case JVM_SIGNATURE_DOUBLE: return "double";
    +template 
    +static traceid artifact_id(const T* ptr) {
    +  assert(ptr != nullptr, "invariant");
    +  return JfrTraceId::load_raw(ptr);
    +}
    +
    +template 
    +static traceid artifact_tag(const T* ptr, bool leakp) {
    +  assert(ptr != nullptr, "invariant");
    +  if (leakp) {
    +    if (IS_NOT_LEAKP(ptr)) {
    +      SET_LEAKP(ptr);
    +    }
    +    assert(IS_LEAKP(ptr), "invariant");
    +    return artifact_id(ptr);
       }
    -  assert(false, "invalid type array klass");
    -  return nullptr;
    +  if (not_used(ptr)) {
    +    SET_TRANSIENT(ptr);
    +  }
    +  assert(used(ptr), "invariant");
    +  return artifact_id(ptr);
     }
     
    -static Symbol* primitive_symbol(KlassPtr type_array_klass) {
    -  if (type_array_klass == nullptr) {
    -    // void.class
    -    static Symbol* const void_class_name = SymbolTable::probe("void", 4);
    -    assert(void_class_name != nullptr, "invariant");
    -    return void_class_name;
    +static inline bool should_do_cld_klass(const Klass* klass, bool leakp) {
    +  return klass != nullptr && _artifacts->should_do_cld_klass(klass, leakp);
    +}
    +
    +static inline KlassPtr get_cld_klass(CldPtr cld, bool leakp) {
    +  if (cld == nullptr) {
    +    return nullptr;
       }
    -  const char* const primitive_type_str = primitive_name(type_array_klass);
    -  assert(primitive_type_str != nullptr, "invariant");
    -  Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, (int)strlen(primitive_type_str));
    -  assert(primitive_type_sym != nullptr, "invariant");
    -  return primitive_type_sym;
    +  assert(leakp ? IS_LEAKP(cld) : used(cld), "invariant");
    +  KlassPtr cld_klass = cld->class_loader_klass();
    +  if (cld_klass == nullptr) {
    +    return nullptr;
    +  }
    +  if (should_do_cld_klass(cld_klass, leakp)) {
    +    if (current_epoch()) {
    +      // This will enqueue the klass, which is important for
    +      // reachability when doing clear and reset at rotation.
    +      JfrTraceId::load(cld_klass);
    +    } else {
    +      artifact_tag(cld_klass, leakp);
    +    }
    +    return cld_klass;
    +  }
    +  return nullptr;
     }
     
    -template 
    -static traceid artifact_id(const T* ptr) {
    -  assert(ptr != nullptr, "invariant");
    -  return JfrTraceId::load_raw(ptr);
    +static inline CldPtr get_cld(ModPtr mod) {
    +  return mod != nullptr ? mod->loader_data() : nullptr;
     }
     
    -static traceid package_id(KlassPtr klass, bool leakp) {
    +static ClassLoaderData* get_cld(const Klass* klass) {
       assert(klass != nullptr, "invariant");
    -  PkgPtr pkg_entry = klass->package();
    -  if (pkg_entry == nullptr) {
    -    return 0;
    -  }
    -  if (leakp) {
    -    SET_LEAKP(pkg_entry);
    +  if (klass->is_objArray_klass()) {
    +    klass = ObjArrayKlass::cast(klass)->bottom_klass();
       }
    -  // package implicitly tagged already
    -  return artifact_id(pkg_entry);
    +  return klass->is_non_strong_hidden() ? nullptr : klass->class_loader_data();
    +}
    +
    +static inline ModPtr get_module(PkgPtr pkg) {
    +  return pkg != nullptr ? pkg->module() : nullptr;
    +}
    +
    +static inline PkgPtr get_package(KlassPtr klass) {
    +  return klass != nullptr ? klass->package() : nullptr;
    +}
    +
    +static inline KlassPtr get_module_cld_klass(KlassPtr klass, bool leakp) {
    +  assert(klass != nullptr, "invariant");
    +  return get_cld_klass(get_cld(get_module(get_package(klass))), leakp);
    +}
    +
    +static traceid cld_id(CldPtr cld, bool leakp) {
    +  assert(cld != nullptr, "invariant");
    +  return artifact_tag(cld, leakp);
     }
     
     static traceid module_id(PkgPtr pkg, bool leakp) {
       assert(pkg != nullptr, "invariant");
    -  ModPtr module_entry = pkg->module();
    -  if (module_entry == nullptr) {
    +  ModPtr mod = get_module(pkg);
    +  if (mod == nullptr) {
         return 0;
       }
    -  if (leakp) {
    -    SET_LEAKP(module_entry);
    -  } else {
    -    SET_TRANSIENT(module_entry);
    +  CldPtr cld = get_cld(mod);
    +  if (cld != nullptr) {
    +    cld_id(cld, leakp);
       }
    -  return artifact_id(module_entry);
    +  return artifact_tag(mod, leakp);
    +}
    +
    +static traceid package_id(KlassPtr klass, bool leakp) {
    +  assert(klass != nullptr, "invariant");
    +  PkgPtr pkg = get_package(klass);
    +  if (pkg == nullptr) {
    +    return 0;
    +  }
    +  // Ensure module and its CLD gets tagged.
    +  module_id(pkg, leakp);
    +  return artifact_tag(pkg, leakp);
     }
     
     static traceid method_id(KlassPtr klass, MethodPtr method) {
    @@ -162,16 +221,6 @@ static traceid method_id(KlassPtr klass, MethodPtr method) {
       return METHOD_ID(klass, method);
     }
     
    -static traceid cld_id(CldPtr cld, bool leakp) {
    -  assert(cld != nullptr, "invariant");
    -  if (leakp) {
    -    SET_LEAKP(cld);
    -  } else {
    -    SET_TRANSIENT(cld);
    -  }
    -  return artifact_id(cld);
    -}
    -
     template 
     static s4 get_flags(const T* ptr) {
       assert(ptr != nullptr, "invariant");
    @@ -183,73 +232,203 @@ static u4 get_primitive_flags() {
       return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
     }
     
    -static ClassLoaderData* get_cld(const Klass* klass) {
    -  assert(klass != nullptr, "invariant");
    -  if (klass->is_objArray_klass()) {
    -    klass = ObjArrayKlass::cast(klass)->bottom_klass();
    +class PackageFieldSelector {
    + public:
    +  typedef PkgPtr TypePtr;
    +  static TypePtr select(KlassPtr klass) {
    +    assert(klass != nullptr, "invariant");
    +    return klass->package();
       }
    -  if (klass->is_non_strong_hidden()) return nullptr;
    -  return klass->class_loader_data();
    -}
    +};
    +
    +class ModuleFieldSelector {
    + public:
    +  typedef ModPtr TypePtr;
    +  static TypePtr select(KlassPtr klass) {
    +    assert(klass != nullptr, "invariant");
    +    PkgPtr pkg = klass->package();
    +    return pkg != nullptr ? pkg->module() : nullptr;
    +  }
    +};
    +
    +class KlassCldFieldSelector {
    + public:
    +  typedef CldPtr TypePtr;
    +  static TypePtr select(KlassPtr klass) {
    +    assert(klass != nullptr, "invariant");
    +    return get_cld(klass);
    +  }
    +};
    +
    +class ModuleCldFieldSelector {
    + public:
    +  typedef CldPtr TypePtr;
    +  static TypePtr select(KlassPtr klass) {
    +    assert(klass != nullptr, "invariant");
    +    ModPtr mod = ModuleFieldSelector::select(klass);
    +    return mod != nullptr ? mod->loader_data() : nullptr;
    +  }
    +};
    +
    +template 
    +class SerializePredicate {
    +  bool _class_unload;
    + public:
    +  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
    +  bool operator()(T const& value) {
    +    assert(value != nullptr, "invariant");
    +    return _class_unload ? _artifacts->should_do_unloading_artifact(value) : IS_NOT_SERIALIZED(value);
    +  }
    +};
    +
    +template <>
    +class SerializePredicate {
    +  bool _class_unload;
    +public:
    +  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
    +  bool operator()(const Klass* klass) {
    +    assert(klass != nullptr, "invariant");
    +    return _class_unload ? true : IS_NOT_SERIALIZED(klass);
    +  }
    +};
    +
    +template <>
    +class SerializePredicate {
    +  bool _class_unload;
    +public:
    +  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
    +  bool operator()(const Method* method) {
    +    assert(method != nullptr, "invariant");
    +    return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method);
    +  }
    +};
     
     template 
     static void set_serialized(const T* ptr) {
       assert(ptr != nullptr, "invariant");
    -  SET_SERIALIZED(ptr);
    -  assert(IS_SERIALIZED(ptr), "invariant");
       if (current_epoch()) {
         CLEAR_THIS_EPOCH_CLEARED_BIT(ptr);
       }
    +  SET_SERIALIZED(ptr);
    +  assert(IS_SERIALIZED(ptr), "invariant");
     }
     
     /*
    - * In C++03, functions used as template parameters must have external linkage;
    - * this restriction was removed in C++11. Change back to "static" and
    - * rename functions when C++11 becomes available.
    + ***********************    Klasses    *************************
    + *
    + * When we process a Klass, we need to process its transitive closure.
    + *
    + * This includes two branches:
    + *
    + * [1] Klass -> CLD -> class_loader_Klass
    + * [2] Klass -> PackageEntry -> ModuleEntry -> CLD -> class_loader_Klass
    + *
    + *    A Klass viewed as this closure becomes a node in a binary tree:
    + *
    + *                           Klass
    + *                             O
    + *                            / \
    + *                           /   \
    + *                      [1] O     O [2]
    + *
    + * We write the Klass and tag the artifacts in its closure (subtree)
    + * using preorder traversal by recursing the class_loader_Klass(es).
      *
    - * The weird naming is an effort to decrease the risk of name clashes.
      */
     
    -static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp) {
    +static void do_write_klass(JfrCheckpointWriter* writer, CldPtr cld, KlassPtr klass, bool leakp) {
       assert(writer != nullptr, "invariant");
       assert(_artifacts != nullptr, "invariant");
       assert(klass != nullptr, "invariant");
       writer->write(artifact_id(klass));
    -  ClassLoaderData* cld = get_cld(klass);
       writer->write(cld != nullptr ? cld_id(cld, leakp) : 0);
       writer->write(mark_symbol(klass, leakp));
       writer->write(package_id(klass, leakp));
       writer->write(klass->modifier_flags());
       writer->write(klass->is_hidden());
    -  return 1;
    +  if (!leakp) {
    +    set_serialized(klass);
    +  }
    +}
    +
    +static inline bool should_write_cld_klass(KlassPtr klass, bool leakp) {
    +  return klass != nullptr && (leakp || IS_NOT_SERIALIZED(klass));
    +}
    +
    +static void write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp, int& elements) {
    +  assert(elements >= 0, "invariant");
    +  ClassLoaderData* cld = get_cld(klass);
    +  do_write_klass(writer, cld, klass, leakp);
    +  ++elements;
    +  if (cld != nullptr) {
    +    // Write the klass for the direct cld.
    +    KlassPtr cld_klass = get_cld_klass(cld, leakp);
    +    if (should_write_cld_klass(cld_klass, leakp)) {
    +      write_klass(writer, cld_klass, leakp, elements);
    +    }
    +  }
    +  KlassPtr mod_klass = get_module_cld_klass(klass, leakp);
    +  if (should_write_cld_klass(mod_klass, leakp)) {
    +    // Write the klass for the module cld.
    +    write_klass(writer, mod_klass, leakp, elements);
    +  }
     }
     
    +/*
    + * In C++03, functions used as template parameters must have external linkage;
    + * this restriction was removed in C++11. Change back to "static" and
    + * rename functions when C++11 becomes available.
    + *
    + * The weird naming is an effort to decrease the risk of name clashes.
    + */
     int write__klass(JfrCheckpointWriter* writer, const void* k) {
       assert(k != nullptr, "invariant");
    -  KlassPtr klass = (KlassPtr)k;
    -  set_serialized(klass);
    -  return write_klass(writer, klass, false);
    +  KlassPtr klass = static_cast(k);
    +  int elements = 0;
    +  write_klass(writer, klass, false, elements);
    +  return elements;
     }
     
     int write__klass__leakp(JfrCheckpointWriter* writer, const void* k) {
       assert(k != nullptr, "invariant");
    -  KlassPtr klass = (KlassPtr)k;
    +  KlassPtr klass = static_cast(k);
       CLEAR_LEAKP(klass);
    -  return write_klass(writer, klass, true);
    +  int elements = 0;
    +  write_klass(writer, klass, true, elements);
    +  return elements;
     }
     
    -static bool is_implied(const Klass* klass) {
    -  assert(klass != nullptr, "invariant");
    -  return klass->is_subclass_of(vmClasses::ClassLoader_klass()) || klass == vmClasses::Object_klass();
    -}
    +static int primitives_count = 9;
     
    -static void do_klass(Klass* klass) {
    -  assert(klass != nullptr, "invariant");
    -  assert(_flushpoint ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass), "invariant");
    -  assert(_subsystem_callback != nullptr, "invariant");
    -  _subsystem_callback->do_artifact(klass);
    +static const char* primitive_name(KlassPtr type_array_klass) {
    +  switch (type_array_klass->name()->base()[1]) {
    +    case JVM_SIGNATURE_BOOLEAN: return "boolean";
    +    case JVM_SIGNATURE_BYTE: return "byte";
    +    case JVM_SIGNATURE_CHAR: return "char";
    +    case JVM_SIGNATURE_SHORT: return "short";
    +    case JVM_SIGNATURE_INT: return "int";
    +    case JVM_SIGNATURE_LONG: return "long";
    +    case JVM_SIGNATURE_FLOAT: return "float";
    +    case JVM_SIGNATURE_DOUBLE: return "double";
    +  }
    +  assert(false, "invalid type array klass");
    +  return nullptr;
     }
     
    +static Symbol* primitive_symbol(KlassPtr type_array_klass) {
    +  if (type_array_klass == nullptr) {
    +    // void.class
    +    static Symbol* const void_class_name = SymbolTable::probe("void", 4);
    +    assert(void_class_name != nullptr, "invariant");
    +    return void_class_name;
    +  }
    +  const char* const primitive_type_str = primitive_name(type_array_klass);
    +  assert(primitive_type_str != nullptr, "invariant");
    +  Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str,
    +                                                        (int)strlen(primitive_type_str));
    +  assert(primitive_type_sym != nullptr, "invariant");
    +  return primitive_type_sym;
    +}
     
     static traceid primitive_id(KlassPtr array_klass) {
       if (array_klass == nullptr) {
    @@ -271,148 +450,69 @@ static void write_primitive(JfrCheckpointWriter* writer, KlassPtr type_array_kla
       writer->write(false);
     }
     
    -static void do_loader_klass(const Klass* klass) {
    -  if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) {
    -    if (_leakp_writer != nullptr) {
    -      SET_LEAKP(klass);
    -    }
    -    SET_TRANSIENT(klass);
    -    _subsystem_callback->do_artifact(klass);
    -  }
    -}
    -
    -static bool register_klass_unload(Klass* klass) {
    -  assert(klass != nullptr, "invariant");
    -  return JfrKlassUnloading::on_unload(klass);
    -}
    -
    -static void do_unloading_klass(Klass* klass) {
    -  assert(klass != nullptr, "invariant");
    -  assert(_subsystem_callback != nullptr, "invariant");
    -  if (register_klass_unload(klass)) {
    -    _subsystem_callback->do_artifact(klass);
    -    do_loader_klass(klass->class_loader_data()->class_loader_klass());
    -  }
    -}
    -
    -/*
    - * Abstract klasses are filtered out unconditionally.
    - * If a klass is not yet initialized, i.e yet to run its 
    - * it is also filtered out so we don't accidentally
    - * trigger initialization.
    - */
    -static bool is_classloader_klass_allowed(const Klass* k) {
    -  assert(k != nullptr, "invariant");
    -  return !(k->is_abstract() || k->should_be_initialized());
    -}
    -
    -static void do_classloaders() {
    -  for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) {
    -    Klass* subk = iter.klass();
    -    if (is_classloader_klass_allowed(subk)) {
    -      do_loader_klass(subk);
    -    }
    -  }
    +static bool is_initial_typeset_for_chunk() {
    +  return _initial_type_set && !unloading();
     }
     
    -static int primitives_count = 9;
    -
     // A mirror representing a primitive class (e.g. int.class) has no reified Klass*,
     // instead it has an associated TypeArrayKlass* (e.g. int[].class).
     // We can use the TypeArrayKlass* as a proxy for deriving the id of the primitive class.
     // The exception is the void.class, which has neither a Klass* nor a TypeArrayKlass*.
     // It will use a reserved constant.
     static void do_primitives() {
    -  // Only write the primitive classes once per chunk.
    -  if (is_initial_typeset_for_chunk()) {
    -    write_primitive(_writer, Universe::boolArrayKlassObj());
    -    write_primitive(_writer, Universe::byteArrayKlassObj());
    -    write_primitive(_writer, Universe::charArrayKlassObj());
    -    write_primitive(_writer, Universe::shortArrayKlassObj());
    -    write_primitive(_writer, Universe::intArrayKlassObj());
    -    write_primitive(_writer, Universe::longArrayKlassObj());
    -    write_primitive(_writer, Universe::floatArrayKlassObj());
    -    write_primitive(_writer, Universe::doubleArrayKlassObj());
    -    write_primitive(_writer, nullptr); // void.class
    -  }
    +  assert(is_initial_typeset_for_chunk(), "invariant");
    +  write_primitive(_writer, Universe::boolArrayKlassObj());
    +  write_primitive(_writer, Universe::byteArrayKlassObj());
    +  write_primitive(_writer, Universe::charArrayKlassObj());
    +  write_primitive(_writer, Universe::shortArrayKlassObj());
    +  write_primitive(_writer, Universe::intArrayKlassObj());
    +  write_primitive(_writer, Universe::longArrayKlassObj());
    +  write_primitive(_writer, Universe::floatArrayKlassObj());
    +  write_primitive(_writer, Universe::doubleArrayKlassObj());
    +  write_primitive(_writer, nullptr); // void.class
     }
     
    -static void do_object() {
    -  SET_TRANSIENT(vmClasses::Object_klass());
    -  do_klass(vmClasses::Object_klass());
    -}
    -
    -static void do_klasses() {
    -  if (_class_unload) {
    -    ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass);
    -    return;
    -  }
    -  JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch());
    -  do_classloaders();
    -  do_primitives();
    -  do_object();
    -}
    -
    -template 
    -static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) {
    -  assert(callback != nullptr, "invariant");
    -  assert(value != nullptr, "invariant");
    -  if (USED_PREVIOUS_EPOCH(value)) {
    -    callback->do_artifact(value);
    -  }
    -  if (IS_SERIALIZED(value)) {
    -    CLEAR_SERIALIZED(value);
    -  }
    -  assert(IS_NOT_SERIALIZED(value), "invariant");
    -}
    -
    -static void do_previous_epoch_klass(JfrArtifactClosure* callback, const Klass* value) {
    -  assert(callback != nullptr, "invariant");
    -  assert(value != nullptr, "invariant");
    -  if (USED_PREVIOUS_EPOCH(value)) {
    -    callback->do_artifact(value);
    +static void do_unloading_klass(Klass* klass) {
    +  assert(klass != nullptr, "invariant");
    +  assert(_subsystem_callback != nullptr, "invariant");
    +  if (JfrKlassUnloading::on_unload(klass)) {
    +    _subsystem_callback->do_artifact(klass);
       }
     }
     
    -static void do_klass_on_clear(Klass* klass) {
    +static void do_klass(Klass* klass) {
       assert(klass != nullptr, "invariant");
    +  assert(used(klass), "invariant");
       assert(_subsystem_callback != nullptr, "invariant");
    -  do_previous_epoch_klass(_subsystem_callback, klass);
    +  _subsystem_callback->do_artifact(klass);
     }
     
    -static void do_loader_klass_on_clear(const Klass* klass) {
    -  if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) {
    -    if (_leakp_writer != nullptr) {
    -      SET_LEAKP(klass);
    -    }
    -    SET_TRANSIENT(klass);
    -    do_previous_epoch_klass(_subsystem_callback, klass);
    +static void do_klasses() {
    +  if (unloading()) {
    +    ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass);
    +    return;
       }
    -}
    -
    -static void do_classloaders_on_clear() {
    -  for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) {
    -    Klass* subk = iter.klass();
    -    if (is_classloader_klass_allowed(subk)) {
    -      do_loader_klass_on_clear(subk);
    -    }
    +  if (is_initial_typeset_for_chunk()) {
    +    // Only write the primitive classes once per chunk.
    +    do_primitives();
       }
    +  JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch());
     }
     
    -static void do_object_on_clear() {
    -  SET_TRANSIENT(vmClasses::Object_klass());
    -  do_klass_on_clear(vmClasses::Object_klass());
    +static void do_klass_on_clear(Klass* klass) {
    +  do_artifact(klass);
     }
     
     static void do_all_klasses() {
       ClassLoaderDataGraph::classes_do(&do_klass_on_clear);
    -  do_classloaders_on_clear();
    -  do_object_on_clear();
     }
     
    +// KlassWriter.
     typedef SerializePredicate KlassPredicate;
     typedef JfrPredicatedTypeWriterImplHost KlassWriterImpl;
     typedef JfrTypeWriterHost KlassWriter;
    +
    +// Klass registration.
     typedef CompositeFunctor KlassWriterRegistration;
     typedef JfrArtifactCallbackHost KlassCallback;
     
    @@ -422,29 +522,31 @@ class LeakPredicate {
       LeakPredicate(bool class_unload) {}
       bool operator()(const Klass* klass) {
         assert(klass != nullptr, "invariant");
    -    return IS_LEAKP(klass) || is_implied(klass);
    +    return IS_LEAKP(klass);
       }
     };
     
    +// KlassWriter for leakp. Only used during start or rotation, i.e. the previous epoch.
     typedef LeakPredicate LeakKlassPredicate;
     typedef JfrPredicatedTypeWriterImplHost LeakKlassWriterImpl;
     typedef JfrTypeWriterHost LeakKlassWriter;
     
    +// Composite KlassWriter with registration.
     typedef CompositeFunctor CompositeKlassWriter;
     typedef CompositeFunctor CompositeKlassWriterRegistration;
     typedef JfrArtifactCallbackHost CompositeKlassCallback;
     
    -static bool write_klasses() {
    +static void write_klasses() {
       assert(!_artifacts->has_klass_entries(), "invariant");
       assert(_writer != nullptr, "invariant");
       KlassArtifactRegistrator reg(_artifacts);
    -  KlassWriter kw(_writer, _class_unload);
    +  KlassWriter kw(_writer, unloading());
       KlassWriterRegistration kwr(&kw, ®);
       if (_leakp_writer == nullptr) {
         KlassCallback callback(&_subsystem_callback, &kwr);
         do_klasses();
       } else {
    -    LeakKlassWriter lkw(_leakp_writer, _class_unload);
    +    LeakKlassWriter lkw(_leakp_writer, unloading());
         CompositeKlassWriter ckw(&lkw, &kw);
         CompositeKlassWriterRegistration ckwr(&ckw, ®);
         CompositeKlassCallback callback(&_subsystem_callback, &ckwr);
    @@ -455,32 +557,26 @@ static bool write_klasses() {
         // their count is not automatically incremented.
         kw.add(primitives_count);
       }
    -  if (is_complete()) {
    -    return false;
    -  }
       _artifacts->tally(kw);
    -  return true;
     }
     
    -static bool write_klasses_on_clear() {
    +static void write_klasses_on_clear() {
       assert(!_artifacts->has_klass_entries(), "invariant");
       assert(_writer != nullptr, "invariant");
       assert(_leakp_writer != nullptr, "invariant");
       KlassArtifactRegistrator reg(_artifacts);
    -  KlassWriter kw(_writer, _class_unload);
    +  KlassWriter kw(_writer, unloading());
       KlassWriterRegistration kwr(&kw, ®);
    -  LeakKlassWriter lkw(_leakp_writer, _class_unload);
    +  LeakKlassWriter lkw(_leakp_writer, unloading());
       CompositeKlassWriter ckw(&lkw, &kw);
       CompositeKlassWriterRegistration ckwr(&ckw, ®);
       CompositeKlassCallback callback(&_subsystem_callback, &ckwr);
       do_all_klasses();
    -  if (is_complete()) {
    -    return false;
    -  }
       _artifacts->tally(kw);
    -  return true;
     }
     
    +/***** Packages *****/
    +
     static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) {
       assert(writer != nullptr, "invariant");
       assert(_artifacts != nullptr, "invariant");
    @@ -494,98 +590,101 @@ static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) {
     
     int write__package(JfrCheckpointWriter* writer, const void* p) {
       assert(p != nullptr, "invariant");
    -  PkgPtr pkg = (PkgPtr)p;
    +  PkgPtr pkg = static_cast(p);
       set_serialized(pkg);
       return write_package(writer, pkg, false);
     }
     
     int write__package__leakp(JfrCheckpointWriter* writer, const void* p) {
       assert(p != nullptr, "invariant");
    -  PkgPtr pkg = (PkgPtr)p;
    +  PkgPtr pkg = static_cast(p);
       CLEAR_LEAKP(pkg);
       return write_package(writer, pkg, true);
     }
     
    -static void do_package(PackageEntry* entry) {
    -  do_previous_epoch_artifact(_subsystem_callback, entry);
    -}
    -
    -static void do_packages() {
    -  ClassLoaderDataGraph::packages_do(&do_package);
    -}
    -
    -class PackageFieldSelector {
    - public:
    -  typedef PkgPtr TypePtr;
    -  static TypePtr select(KlassPtr klass) {
    -    assert(klass != nullptr, "invariant");
    -    return klass->package();
    -  }
    -};
     
    +// PackageWriter.
     typedef SerializePredicate PackagePredicate;
     typedef JfrPredicatedTypeWriterImplHost PackageWriterImpl;
     typedef JfrTypeWriterHost PackageWriter;
    -typedef CompositeFunctor > PackageWriterWithClear;
    +typedef JfrArtifactCallbackHost PackageCallback;
    +
    +// PackageWriter used during flush or unloading i.e. the current epoch.
     typedef KlassToFieldEnvelope KlassPackageWriter;
    -typedef JfrArtifactCallbackHost PackageCallback;
     
    +// PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch.
    +typedef CompositeFunctor > PackageWriterWithClear;
    +typedef JfrArtifactCallbackHost PackageClearCallback;
    +
    +// PackageWriter for leakp. Only used during start or rotation, i.e. the previous epoch.
     typedef LeakPredicate LeakPackagePredicate;
     typedef JfrPredicatedTypeWriterImplHost LeakPackageWriterImpl;
     typedef JfrTypeWriterHost LeakPackageWriter;
     
    +// Composite PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch.
     typedef CompositeFunctor CompositePackageWriter;
    -typedef KlassToFieldEnvelope KlassCompositePackageWriter;
    -typedef KlassToFieldEnvelope KlassPackageWriterWithClear;
     typedef CompositeFunctor > CompositePackageWriterWithClear;
    -typedef JfrArtifactCallbackHost CompositePackageCallback;
    +typedef JfrArtifactCallbackHost CompositePackageClearCallback;
    +
    +static void do_package(PackageEntry* pkg) {
    +  do_artifact(pkg);
    +}
    +
    +static void do_all_packages() {
    +  ClassLoaderDataGraph::packages_do(&do_package);
    +}
    +
    +static void do_all_packages(PackageWriter& pw) {
    +  do_all_packages();
    +  _artifacts->tally(pw);
    +}
    +
    +static void do_packages(PackageWriter& pw) {
    +  KlassPackageWriter kpw(&pw);
    +  _artifacts->iterate_klasses(kpw);
    +  _artifacts->tally(pw);
    +}
    +
    +static void write_packages_with_leakp(PackageWriter& pw) {
    +  assert(_writer != nullptr, "invariant");
    +  assert(_leakp_writer != nullptr, "invariant");
    +  assert(previous_epoch(), "invariant");
    +  LeakPackageWriter lpw(_leakp_writer, unloading());
    +  CompositePackageWriter cpw(&lpw, &pw);
    +  ClearArtifact clear;
    +  CompositePackageWriterWithClear cpwwc(&cpw, &clear);
    +  CompositePackageClearCallback callback(&_subsystem_callback, &cpwwc);
    +  do_all_packages(pw);
    +}
     
     static void write_packages() {
       assert(_writer != nullptr, "invariant");
    -  PackageWriter pw(_writer, _class_unload);
    -  KlassPackageWriter kpw(&pw);
    +  PackageWriter pw(_writer, unloading());
       if (current_epoch()) {
    -    _artifacts->iterate_klasses(kpw);
    -    _artifacts->tally(pw);
    +    do_packages(pw);
         return;
       }
       assert(previous_epoch(), "invariant");
       if (_leakp_writer == nullptr) {
    -    _artifacts->iterate_klasses(kpw);
         ClearArtifact clear;
         PackageWriterWithClear pwwc(&pw, &clear);
    -    PackageCallback callback(&_subsystem_callback, &pwwc);
    -    do_packages();
    -  } else {
    -    LeakPackageWriter lpw(_leakp_writer, _class_unload);
    -    CompositePackageWriter cpw(&lpw, &pw);
    -    KlassCompositePackageWriter kcpw(&cpw);
    -    _artifacts->iterate_klasses(kcpw);
    -    ClearArtifact clear;
    -    CompositePackageWriterWithClear cpwwc(&cpw, &clear);
    -    CompositePackageCallback callback(&_subsystem_callback, &cpwwc);
    -    do_packages();
    +    PackageClearCallback callback(&_subsystem_callback, &pwwc);
    +    do_all_packages(pw);
    +    return;
       }
    -  _artifacts->tally(pw);
    +  write_packages_with_leakp(pw);
     }
     
     static void write_packages_on_clear() {
       assert(_writer != nullptr, "invariant");
       assert(_leakp_writer != nullptr, "invariant");
       assert(previous_epoch(), "invariant");
    -  PackageWriter pw(_writer, _class_unload);
    -  KlassPackageWriter kpw(&pw);
    -  LeakPackageWriter lpw(_leakp_writer, _class_unload);
    -  CompositePackageWriter cpw(&lpw, &pw);
    -  KlassCompositePackageWriter kcpw(&cpw);
    -  _artifacts->iterate_klasses(kcpw);
    -  ClearArtifact clear;
    -  CompositePackageWriterWithClear cpwwc(&cpw, &clear);
    -  CompositePackageCallback callback(&_subsystem_callback, &cpwwc);
    -  do_packages();
    -  _artifacts->tally(pw);
    +  PackageWriter pw(_writer, unloading());
    +  write_packages_with_leakp(pw);
     }
     
    +/***** Modules *****/
    +
     static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) {
       assert(mod != nullptr, "invariant");
       assert(_artifacts != nullptr, "invariant");
    @@ -599,99 +698,101 @@ static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) {
     
     int write__module(JfrCheckpointWriter* writer, const void* m) {
       assert(m != nullptr, "invariant");
    -  ModPtr mod = (ModPtr)m;
    +  ModPtr mod = static_cast(m);
       set_serialized(mod);
       return write_module(writer, mod, false);
     }
     
     int write__module__leakp(JfrCheckpointWriter* writer, const void* m) {
       assert(m != nullptr, "invariant");
    -  ModPtr mod = (ModPtr)m;
    +  ModPtr mod = static_cast(m);
       CLEAR_LEAKP(mod);
       return write_module(writer, mod, true);
     }
     
    -static void do_module(ModuleEntry* entry) {
    -  do_previous_epoch_artifact(_subsystem_callback, entry);
    -}
    -
    -static void do_modules() {
    -  ClassLoaderDataGraph::modules_do(&do_module);
    -}
    -
    -class ModuleFieldSelector {
    - public:
    -  typedef ModPtr TypePtr;
    -  static TypePtr select(KlassPtr klass) {
    -    assert(klass != nullptr, "invariant");
    -    PkgPtr pkg = klass->package();
    -    return pkg != nullptr ? pkg->module() : nullptr;
    -  }
    -};
    -
    +// ModuleWriter.
     typedef SerializePredicate ModulePredicate;
     typedef JfrPredicatedTypeWriterImplHost ModuleWriterImpl;
     typedef JfrTypeWriterHost ModuleWriter;
    -typedef CompositeFunctor > ModuleWriterWithClear;
    -typedef JfrArtifactCallbackHost ModuleCallback;
    +typedef JfrArtifactCallbackHost ModuleCallback;
    +
    +// ModuleWriter used during flush or unloading i.e. the current epoch.
     typedef KlassToFieldEnvelope KlassModuleWriter;
     
    +// ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch.
    +typedef CompositeFunctor > ModuleWriterWithClear;
    +typedef JfrArtifactCallbackHost ModuleClearCallback;
    +
    +// ModuleWriter for leakp. Only used during start or rotation, i.e. the previous epoch.
     typedef LeakPredicate LeakModulePredicate;
     typedef JfrPredicatedTypeWriterImplHost LeakModuleWriterImpl;
     typedef JfrTypeWriterHost LeakModuleWriter;
     
    +// Composite ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch.
     typedef CompositeFunctor CompositeModuleWriter;
    -typedef KlassToFieldEnvelope KlassCompositeModuleWriter;
     typedef CompositeFunctor > CompositeModuleWriterWithClear;
    -typedef JfrArtifactCallbackHost CompositeModuleCallback;
    +typedef JfrArtifactCallbackHost CompositeModuleClearCallback;
    +
    +static void do_module(ModuleEntry* mod) {
    +  do_artifact(mod);
    +}
    +
    +static void do_all_modules() {
    +  ClassLoaderDataGraph::modules_do(&do_module);
    +}
    +
    +static void do_all_modules(ModuleWriter& mw) {
    +  do_all_modules();
    +  _artifacts->tally(mw);
    +}
    +
    +static void do_modules(ModuleWriter& mw) {
    +  KlassModuleWriter kmw(&mw);
    +  _artifacts->iterate_klasses(kmw);
    +  _artifacts->tally(mw);
    +}
    +
    +static void write_modules_with_leakp(ModuleWriter& mw) {
    +  assert(_writer != nullptr, "invariant");
    +  assert(_leakp_writer != nullptr, "invariant");
    +  assert(previous_epoch(), "invariant");
    +  LeakModuleWriter lmw(_leakp_writer, unloading());
    +  CompositeModuleWriter cmw(&lmw, &mw);
    +  ClearArtifact clear;
    +  CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
    +  CompositeModuleClearCallback callback(&_subsystem_callback, &cmwwc);
    +  do_all_modules(mw);
    +}
     
     static void write_modules() {
       assert(_writer != nullptr, "invariant");
    -  ModuleWriter mw(_writer, _class_unload);
    -  KlassModuleWriter kmw(&mw);
    +  ModuleWriter mw(_writer, unloading());
       if (current_epoch()) {
    -    _artifacts->iterate_klasses(kmw);
    -    _artifacts->tally(mw);
    +    do_modules(mw);
         return;
       }
       assert(previous_epoch(), "invariant");
       if (_leakp_writer == nullptr) {
    -    _artifacts->iterate_klasses(kmw);
         ClearArtifact clear;
         ModuleWriterWithClear mwwc(&mw, &clear);
    -    ModuleCallback callback(&_subsystem_callback, &mwwc);
    -    do_modules();
    -  } else {
    -    LeakModuleWriter lmw(_leakp_writer, _class_unload);
    -    CompositeModuleWriter cmw(&lmw, &mw);
    -    KlassCompositeModuleWriter kcpw(&cmw);
    -    _artifacts->iterate_klasses(kcpw);
    -    ClearArtifact clear;
    -    CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
    -    CompositeModuleCallback callback(&_subsystem_callback, &cmwwc);
    -    do_modules();
    +    ModuleClearCallback callback(&_subsystem_callback, &mwwc);
    +    do_all_modules(mw);
    +    return;
       }
    -  _artifacts->tally(mw);
    +  write_modules_with_leakp(mw);
     }
     
     static void write_modules_on_clear() {
       assert(_writer != nullptr, "invariant");
       assert(_leakp_writer != nullptr, "invariant");
       assert(previous_epoch(), "invariant");
    -  ModuleWriter mw(_writer, _class_unload);
    -  KlassModuleWriter kmw(&mw);
    -  LeakModuleWriter lmw(_leakp_writer, _class_unload);
    -  CompositeModuleWriter cmw(&lmw, &mw);
    -  KlassCompositeModuleWriter kcpw(&cmw);
    -  _artifacts->iterate_klasses(kcpw);
    -  ClearArtifact clear;
    -  CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
    -  CompositeModuleCallback callback(&_subsystem_callback, &cmwwc);
    -  do_modules();
    -  _artifacts->tally(mw);
    +  ModuleWriter mw(_writer, unloading());
    +  write_modules_with_leakp(mw);
     }
     
    -static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) {
    +/***** ClassLoaderData - CLD *****/
    +
    +static int write_cld(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) {
       assert(cld != nullptr, "invariant");
       // class loader type
       const Klass* class_loader_klass = cld->class_loader_klass();
    @@ -701,7 +802,7 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp
         writer->write((traceid)0);  // class loader type id (absence of)
         writer->write(get_bootstrap_name(leakp)); // maps to synthetic name -> "bootstrap"
       } else {
    -    assert(_class_unload ? true : IS_SERIALIZED(class_loader_klass), "invariant");
    +    assert(IS_SERIALIZED(class_loader_klass), "invariant");
         writer->write(artifact_id(cld)); // class loader instance id
         writer->write(artifact_id(class_loader_klass)); // class loader type id
         writer->write(mark_symbol(cld->name(), leakp)); // class loader instance name
    @@ -709,146 +810,127 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp
       return 1;
     }
     
    -int write__classloader(JfrCheckpointWriter* writer, const void* c) {
    +int write__cld(JfrCheckpointWriter* writer, const void* c) {
       assert(c != nullptr, "invariant");
    -  CldPtr cld = (CldPtr)c;
    +  CldPtr cld = static_cast(c);
       set_serialized(cld);
    -  return write_classloader(writer, cld, false);
    +  return write_cld(writer, cld, false);
     }
     
    -int write__classloader__leakp(JfrCheckpointWriter* writer, const void* c) {
    +int write__cld__leakp(JfrCheckpointWriter* writer, const void* c) {
       assert(c != nullptr, "invariant");
    -  CldPtr cld = (CldPtr)c;
    +  CldPtr cld = static_cast(c);
       CLEAR_LEAKP(cld);
    -  return write_classloader(writer, cld, true);
    +  return write_cld(writer, cld, true);
     }
     
    -static void do_class_loader_data(ClassLoaderData* cld) {
    -  do_previous_epoch_artifact(_subsystem_callback, cld);
    -}
    +// CldWriter.
    +typedef SerializePredicate CldPredicate;
    +typedef JfrPredicatedTypeWriterImplHost CldWriterImpl;
    +typedef JfrTypeWriterHost CldWriter;
    +typedef JfrArtifactCallbackHost CldCallback;
     
    -class KlassCldFieldSelector {
    - public:
    -  typedef CldPtr TypePtr;
    -  static TypePtr select(KlassPtr klass) {
    -    assert(klass != nullptr, "invariant");
    -    return get_cld(klass);
    -  }
    -};
    +// CldWriter used during flush or unloading i.e. the current epoch.
    +typedef KlassToFieldEnvelope KlassCldWriter;
    +typedef KlassToFieldEnvelope ModuleCldWriter;
    +typedef CompositeFunctor KlassAndModuleCldWriter;
     
    -class ModuleCldFieldSelector {
    -public:
    -  typedef CldPtr TypePtr;
    -  static TypePtr select(KlassPtr klass) {
    -    assert(klass != nullptr, "invariant");
    -    ModPtr mod = ModuleFieldSelector::select(klass);
    -    return mod != nullptr ? mod->loader_data() : nullptr;
    -  }
    -};
    +// CldWriter with clear. Only used during start or rotation, i.e. the previous epoch.
    +typedef CompositeFunctor > CldWriterWithClear;
    +typedef JfrArtifactCallbackHost CldClearCallback;
    +
    +// CldWriter for leakp. Only used during start or rotation, i.e. the previous epoch.
    +typedef LeakPredicate LeakCldPredicate;
    +typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl;
    +typedef JfrTypeWriterHost LeakCldWriter;
    +
    +// Composite CldWriter with clear. Only used during start or rotation, i.e. the previous epoch.
    +typedef CompositeFunctor CompositeCldWriter;
    +typedef CompositeFunctor > CompositeCldWriterWithClear;
    +typedef JfrArtifactCallbackHost CompositeCldClearCallback;
     
     class CLDCallback : public CLDClosure {
      public:
    -  CLDCallback() {}
       void do_cld(ClassLoaderData* cld) {
         assert(cld != nullptr, "invariant");
    -    if (cld->has_class_mirror_holder()) {
    -      return;
    +    if (!cld->has_class_mirror_holder()) {
    +      do_artifact(cld);
         }
    -    do_class_loader_data(cld);
       }
     };
     
    -static void do_class_loaders() {
    +static void do_all_clds() {
       CLDCallback cld_cb;
       ClassLoaderDataGraph::loaded_cld_do(&cld_cb);
     }
     
    -typedef SerializePredicate CldPredicate;
    -typedef JfrPredicatedTypeWriterImplHost CldWriterImpl;
    -typedef JfrTypeWriterHost CldWriter;
    -typedef CompositeFunctor > CldWriterWithClear;
    -typedef JfrArtifactCallbackHost CldCallback;
    -typedef KlassToFieldEnvelope KlassCldWriter;
    -typedef KlassToFieldEnvelope ModuleCldWriter;
    -typedef CompositeFunctor KlassAndModuleCldWriter;
    -
    -typedef LeakPredicate LeakCldPredicate;
    -typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl;
    -typedef JfrTypeWriterHost LeakCldWriter;
    -
    -typedef CompositeFunctor CompositeCldWriter;
    -typedef KlassToFieldEnvelope KlassCompositeCldWriter;
    -typedef KlassToFieldEnvelope ModuleCompositeCldWriter;
    -typedef CompositeFunctor KlassAndModuleCompositeCldWriter;
    -typedef CompositeFunctor > CompositeCldWriterWithClear;
    -typedef JfrArtifactCallbackHost CompositeCldCallback;
    +static void do_all_clds(CldWriter& cldw) {
    +  do_all_clds();
    +  _artifacts->tally(cldw);
    +}
     
    -static void write_classloaders() {
    -  assert(_writer != nullptr, "invariant");
    -  CldWriter cldw(_writer, _class_unload);
    +static void do_clds(CldWriter& cldw) {
       KlassCldWriter kcw(&cldw);
       ModuleCldWriter mcw(&cldw);
       KlassAndModuleCldWriter kmcw(&kcw, &mcw);
    +  _artifacts->iterate_klasses(kmcw);
    +  _artifacts->tally(cldw);
    +}
    +
    +static void write_clds_with_leakp(CldWriter& cldw) {
    +  assert(_writer != nullptr, "invariant");
    +  assert(_leakp_writer != nullptr, "invariant");
    +  assert(previous_epoch(), "invariant");
    +  LeakCldWriter lcldw(_leakp_writer, unloading());
    +  CompositeCldWriter ccldw(&lcldw, &cldw);
    +  ClearArtifact clear;
    +  CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
    +  CompositeCldClearCallback callback(&_subsystem_callback, &ccldwwc);
    +  do_all_clds(cldw);
    +}
    +
    +static void write_clds() {
    +  assert(_writer != nullptr, "invariant");
    +  CldWriter cldw(_writer, unloading());
       if (current_epoch()) {
    -    _artifacts->iterate_klasses(kmcw);
    -    _artifacts->tally(cldw);
    +    do_clds(cldw);
         return;
       }
       assert(previous_epoch(), "invariant");
       if (_leakp_writer == nullptr) {
    -    _artifacts->iterate_klasses(kmcw);
         ClearArtifact clear;
         CldWriterWithClear cldwwc(&cldw, &clear);
    -    CldCallback callback(&_subsystem_callback, &cldwwc);
    -    do_class_loaders();
    -  } else {
    -    LeakCldWriter lcldw(_leakp_writer, _class_unload);
    -    CompositeCldWriter ccldw(&lcldw, &cldw);
    -    KlassCompositeCldWriter kccldw(&ccldw);
    -    ModuleCompositeCldWriter mccldw(&ccldw);
    -    KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw);
    -    _artifacts->iterate_klasses(kmccldw);
    -    ClearArtifact clear;
    -    CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
    -    CompositeCldCallback callback(&_subsystem_callback, &ccldwwc);
    -    do_class_loaders();
    +    CldClearCallback callback(&_subsystem_callback, &cldwwc);
    +    do_all_clds(cldw);
    +    return;
       }
    -  _artifacts->tally(cldw);
    +  write_clds_with_leakp(cldw);
     }
     
    -static void write_classloaders_on_clear() {
    +static void write_clds_on_clear() {
       assert(_writer != nullptr, "invariant");
       assert(_leakp_writer != nullptr, "invariant");
    -  CldWriter cldw(_writer, _class_unload);
    -  KlassCldWriter kcw(&cldw);
    -  ModuleCldWriter mcw(&cldw);
    -  KlassAndModuleCldWriter kmcw(&kcw, &mcw);
    -  LeakCldWriter lcldw(_leakp_writer, _class_unload);
    -  CompositeCldWriter ccldw(&lcldw, &cldw);
    -  KlassCompositeCldWriter kccldw(&ccldw);
    -  ModuleCompositeCldWriter mccldw(&ccldw);
    -  KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw);
    -  _artifacts->iterate_klasses(kmccldw);
    -  ClearArtifact clear;
    -  CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
    -  CompositeCldCallback callback(&_subsystem_callback, &ccldwwc);
    -  do_class_loaders();
    -  _artifacts->tally(cldw);
    +  assert(previous_epoch(), "invariant");
    +  CldWriter cldw(_writer, unloading());
    +  write_clds_with_leakp(cldw);
     }
     
    -static u1 get_visibility(MethodPtr method) {
    -  assert(method != nullptr, "invariant");
    -  return const_cast(method)->is_hidden() ? (u1)1 : (u1)0;
    -}
    +/***** Methods *****/
     
     template <>
     void set_serialized(MethodPtr method) {
       assert(method != nullptr, "invariant");
    -  SET_METHOD_SERIALIZED(method);
    -  assert(METHOD_IS_SERIALIZED(method), "invariant");
       if (current_epoch()) {
         CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method);
       }
    +  assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant");
    +  SET_METHOD_SERIALIZED(method);
    +  assert(METHOD_IS_SERIALIZED(method), "invariant");
    +}
    +
    +static inline u1 get_visibility(MethodPtr method) {
    +  assert(method != nullptr, "invariant");
    +  return const_cast(method)->is_hidden() ? (u1)1 : (u1)0;
     }
     
     static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leakp) {
    @@ -857,58 +939,36 @@ static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leak
       assert(_artifacts != nullptr, "invariant");
       KlassPtr klass = method->method_holder();
       assert(klass != nullptr, "invariant");
    +  assert(used(klass), "invariant");
    +  assert(IS_SERIALIZED(klass), "invariant");
       writer->write(method_id(klass, method));
       writer->write(artifact_id(klass));
       writer->write(mark_symbol(method->name(), leakp));
       writer->write(mark_symbol(method->signature(), leakp));
    -  writer->write((u2)get_flags(method));
    +  writer->write(static_cast(get_flags(method)));
       writer->write(get_visibility(method));
       return 1;
     }
     
     int write__method(JfrCheckpointWriter* writer, const void* m) {
       assert(m != nullptr, "invariant");
    -  MethodPtr method = (MethodPtr)m;
    +  MethodPtr method = static_cast(m);
       set_serialized(method);
       return write_method(writer, method, false);
     }
     
     int write__method__leakp(JfrCheckpointWriter* writer, const void* m) {
       assert(m != nullptr, "invariant");
    -  MethodPtr method = (MethodPtr)m;
    +  MethodPtr method = static_cast(m);
       CLEAR_LEAKP_METHOD(method);
       return write_method(writer, method, true);
     }
    -
    -class BitMapFilter {
    -  ResourceBitMap _bitmap;
    - public:
    -  explicit BitMapFilter(int length = 0) : _bitmap((size_t)length) {}
    -  bool operator()(size_t idx) {
    -    if (_bitmap.size() == 0) {
    -      return true;
    -    }
    -    if (_bitmap.at(idx)) {
    -      return false;
    -    }
    -    _bitmap.set_bit(idx);
    -    return true;
    -  }
    -};
    -
    -class AlwaysTrue {
    - public:
    -  explicit AlwaysTrue(int length = 0) {}
    -  bool operator()(size_t idx) {
    -    return true;
    -  }
    -};
    -
    -template 
    +template 
     class MethodIteratorHost {
      private:
       MethodCallback _method_cb;
       KlassCallback _klass_cb;
    +  KlassUsedPredicate _klass_used_predicate;
       MethodUsedPredicate _method_used_predicate;
       MethodFlagPredicate _method_flag_predicate;
      public:
    @@ -918,6 +978,7 @@ class MethodIteratorHost {
                          bool skip_header = false) :
         _method_cb(writer, class_unload, skip_header),
         _klass_cb(writer, class_unload, skip_header),
    +    _klass_used_predicate(current_epoch),
         _method_used_predicate(current_epoch),
         _method_flag_predicate(current_epoch) {}
     
    @@ -937,7 +998,7 @@ class MethodIteratorHost {
             ik = ik->previous_versions();
           }
         }
    -    return _klass_cb(klass);
    +    return _klass_used_predicate(klass) ? _klass_cb(klass) : true;
       }
     
       int count() const { return _method_cb.count(); }
    @@ -964,37 +1025,42 @@ typedef SerializePredicate MethodPredicate;
     typedef JfrPredicatedTypeWriterImplHost MethodWriterImplTarget;
     typedef Wrapper KlassCallbackStub;
     typedef JfrTypeWriterHost MethodWriterImpl;
    -typedef MethodIteratorHost MethodWriter;
    +typedef MethodIteratorHost MethodWriter;
     
     typedef LeakPredicate LeakMethodPredicate;
     typedef JfrPredicatedTypeWriterImplHost LeakMethodWriterImplTarget;
     typedef JfrTypeWriterHost LeakMethodWriterImpl;
    -typedef MethodIteratorHost LeakMethodWriter;
    -typedef MethodIteratorHost LeakMethodWriter;
    +typedef MethodIteratorHost LeakMethodWriter;
    +typedef MethodIteratorHost LeakMethodWriter;
     typedef CompositeFunctor CompositeMethodWriter;
     
    +static void write_methods_with_leakp(MethodWriter& mw) {
    +  assert(_writer != nullptr, "invariant");
    +  assert(_leakp_writer != nullptr, "invariant");
    +  assert(previous_epoch(), "invariant");
    +  LeakMethodWriter lpmw(_leakp_writer, current_epoch(), unloading());
    +  CompositeMethodWriter cmw(&lpmw, &mw);
    +  _artifacts->iterate_klasses(cmw);
    +  _artifacts->tally(mw);
    +}
    +
     static void write_methods() {
       assert(_writer != nullptr, "invariant");
    -  MethodWriter mw(_writer, current_epoch(), _class_unload);
    +  MethodWriter mw(_writer, current_epoch(), unloading());
       if (_leakp_writer == nullptr) {
         _artifacts->iterate_klasses(mw);
    -  } else {
    -    LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload);
    -    CompositeMethodWriter cmw(&lpmw, &mw);
    -    _artifacts->iterate_klasses(cmw);
    +    _artifacts->tally(mw);
    +    return;
       }
    -  _artifacts->tally(mw);
    +  write_methods_with_leakp(mw);
     }
     
     static void write_methods_on_clear() {
       assert(_writer != nullptr, "invariant");
       assert(_leakp_writer != nullptr, "invariant");
       assert(previous_epoch(), "invariant");
    -  MethodWriter mw(_writer, current_epoch(), _class_unload);
    -  LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload);
    -  CompositeMethodWriter cmw(&lpmw, &mw);
    -  _artifacts->iterate_klasses(cmw);
    -  _artifacts->tally(mw);
    +  MethodWriter mw(_writer, current_epoch(), unloading());
    +  write_methods_with_leakp(mw);
     }
     
     template <>
    @@ -1022,14 +1088,14 @@ static int write_symbol(JfrCheckpointWriter* writer, SymbolEntryPtr entry, bool
     
     int write__symbol(JfrCheckpointWriter* writer, const void* e) {
       assert(e != nullptr, "invariant");
    -  SymbolEntryPtr entry = (SymbolEntryPtr)e;
    +  SymbolEntryPtr entry = static_cast(e);
       set_serialized(entry);
       return write_symbol(writer, entry, false);
     }
     
     int write__symbol__leakp(JfrCheckpointWriter* writer, const void* e) {
       assert(e != nullptr, "invariant");
    -  SymbolEntryPtr entry = (SymbolEntryPtr)e;
    +  SymbolEntryPtr entry = static_cast(e);
       return write_symbol(writer, entry, true);
     }
     
    @@ -1043,14 +1109,14 @@ static int write_string(JfrCheckpointWriter* writer, StringEntryPtr entry, bool
     
     int write__string(JfrCheckpointWriter* writer, const void* e) {
       assert(e != nullptr, "invariant");
    -  StringEntryPtr entry = (StringEntryPtr)e;
    +  StringEntryPtr entry = static_cast(e);
       set_serialized(entry);
       return write_string(writer, entry, false);
     }
     
     int write__string__leakp(JfrCheckpointWriter* writer, const void* e) {
       assert(e != nullptr, "invariant");
    -  StringEntryPtr entry = (StringEntryPtr)e;
    +  StringEntryPtr entry = static_cast(e);
       return write_string(writer, entry, true);
     }
     
    @@ -1071,30 +1137,15 @@ typedef JfrTypeWriterHost LeakStringEntr
     typedef CompositeFunctor CompositeStringWriter;
     
     static void write_symbols_with_leakp() {
    -  assert(_leakp_writer != nullptr, "invariant");
    -  SymbolEntryWriter sw(_writer, _class_unload);
    -  LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload);
    -  CompositeSymbolWriter csw(&lsw, &sw);
    -  _artifacts->iterate_symbols(csw);
    -  StringEntryWriter sew(_writer, _class_unload, true); // skip header
    -  LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header
    -  CompositeStringWriter csew(&lsew, &sew);
    -  _artifacts->iterate_strings(csew);
    -  sw.add(sew.count());
    -  lsw.add(lsew.count());
    -  _artifacts->tally(sw);
    -}
    -
    -static void write_symbols_on_clear() {
       assert(_writer != nullptr, "invariant");
       assert(_leakp_writer != nullptr, "invariant");
       assert(previous_epoch(), "invariant");
    -  SymbolEntryWriter sw(_writer, _class_unload);
    -  LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload);
    +  SymbolEntryWriter sw(_writer, unloading());
    +  LeakSymbolEntryWriter lsw(_leakp_writer, unloading());
       CompositeSymbolWriter csw(&lsw, &sw);
       _artifacts->iterate_symbols(csw);
    -  StringEntryWriter sew(_writer, _class_unload, true); // skip header
    -  LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header
    +  StringEntryWriter sew(_writer, unloading(), true); // skip header
    +  LeakStringEntryWriter lsew(_leakp_writer, unloading(), true); // skip header
       CompositeStringWriter csew(&lsew, &sew);
       _artifacts->iterate_strings(csew);
       sw.add(sew.count());
    @@ -1108,17 +1159,24 @@ static void write_symbols() {
         write_symbols_with_leakp();
         return;
       }
    -  SymbolEntryWriter sw(_writer, _class_unload);
    +  SymbolEntryWriter sw(_writer, unloading());
       _artifacts->iterate_symbols(sw);
    -  StringEntryWriter sew(_writer, _class_unload, true); // skip header
    +  StringEntryWriter sew(_writer, unloading(), true); // skip header
       _artifacts->iterate_strings(sew);
       sw.add(sew.count());
       _artifacts->tally(sw);
     }
     
    +static void write_symbols_on_clear() {
    +  assert(_writer != nullptr, "invariant");
    +  assert(_leakp_writer != nullptr, "invariant");
    +  assert(previous_epoch(), "invariant");
    +  write_symbols_with_leakp();
    +}
    +
     typedef Wrapper ClearKlassBits;
     typedef Wrapper ClearMethodFlag;
    -typedef MethodIteratorHost ClearKlassAndMethods;
    +typedef MethodIteratorHost ClearKlassAndMethods;
     
     static void clear_klasses_and_methods() {
       ClearKlassAndMethods clear(_writer);
    @@ -1165,19 +1223,17 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l
       setup(writer, leakp_writer, class_unload, flushpoint);
       // write order is important because an individual write step
       // might tag an artifact to be written in a subsequent step
    -  if (!write_klasses()) {
    -    return 0;
    -  }
    +  write_klasses();
       write_packages();
       write_modules();
    -  write_classloaders();
    +  write_clds();
       write_methods();
       write_symbols();
       return teardown();
     }
     
     /**
    - * Clear all tags from the previous epoch.
    + * Clear all tags from the previous epoch. Reset support structures.
      */
     void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
       ResourceMark rm;
    @@ -1185,7 +1241,7 @@ void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_w
       write_klasses_on_clear();
       write_packages_on_clear();
       write_modules_on_clear();
    -  write_classloaders_on_clear();
    +  write_clds_on_clear();
       write_methods_on_clear();
       write_symbols_on_clear();
       teardown();
    diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp
    index 0876281d53f..883821f853c 100644
    --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp
    +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp
    @@ -32,7 +32,8 @@
     
     JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(nullptr),
                                                         _klass_list(nullptr),
    -                                                    _total_count(0) {
    +                                                    _total_count(0),
    +                                                    _class_unload(class_unload) {
       initialize(class_unload);
       assert(_klass_list != nullptr, "invariant");
     }
    @@ -41,6 +42,7 @@ static const size_t initial_klass_list_size = 256;
     const int initial_klass_loader_set_size = 64;
     
     void JfrArtifactSet::initialize(bool class_unload) {
    +  _class_unload = class_unload;
       if (_symbol_table == nullptr) {
         _symbol_table = JfrSymbolTable::create();
         assert(_symbol_table != nullptr, "invariant");
    @@ -51,6 +53,11 @@ void JfrArtifactSet::initialize(bool class_unload) {
       // resource allocation
       _klass_list = new GrowableArray(initial_klass_list_size);
       _klass_loader_set = new GrowableArray(initial_klass_loader_set_size);
    +  _klass_loader_leakp_set = new GrowableArray(initial_klass_loader_set_size);
    +
    +  if (class_unload) {
    +    _unloading_set = new GrowableArray(initial_klass_list_size);
    +  }
     }
     
     void JfrArtifactSet::clear() {
    @@ -97,10 +104,27 @@ int JfrArtifactSet::entries() const {
       return _klass_list->length();
     }
     
    -bool JfrArtifactSet::should_do_loader_klass(const Klass* k) {
    +static inline bool not_in_set(GrowableArray* set, const Klass* k) {
    +  assert(set != nullptr, "invariant");
    +  assert(k != nullptr, "invariant");
    +  return !JfrMutablePredicate::test(set, k);
    +}
    +
    +bool JfrArtifactSet::should_do_cld_klass(const Klass* k, bool leakp) {
       assert(k != nullptr, "invariant");
       assert(_klass_loader_set != nullptr, "invariant");
    -  return !JfrMutablePredicate::test(_klass_loader_set, k);
    +  assert(_klass_loader_leakp_set != nullptr, "invariant");
    +  return not_in_set(leakp ? _klass_loader_leakp_set : _klass_loader_set, k);
    +}
    +
    +bool JfrArtifactSet::should_do_unloading_artifact(const void* ptr) {
    +  assert(ptr != nullptr, "invariant");
    +  assert(_class_unload, "invariant");
    +  assert(_unloading_set != nullptr, "invariant");
    +  // The incoming pointers are of all kinds of different types.
    +  // However, we are only interested in set membership.
    +  // Treat them uniformly as const Klass* for simplicity and code reuse.
    +  return not_in_set(_unloading_set, static_cast(ptr));
     }
     
     void JfrArtifactSet::register_klass(const Klass* k) {
    diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp
    index b0c2d989de5..24424fdef3a 100644
    --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp
    +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp
    @@ -114,28 +114,6 @@ class ClearArtifact {
       }
     };
     
    -template 
    -class SerializePredicate {
    -  bool _class_unload;
    - public:
    -  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
    -  bool operator()(T const& value) {
    -    assert(value != nullptr, "invariant");
    -    return _class_unload ? true : IS_NOT_SERIALIZED(value);
    -  }
    -};
    -
    -template <>
    -class SerializePredicate {
    -  bool _class_unload;
    - public:
    -  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
    -  bool operator()(const Method* method) {
    -    assert(method != nullptr, "invariant");
    -    return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method);
    -  }
    -};
    -
     template 
     class SymbolPredicate {
       bool _class_unload;
    @@ -150,11 +128,23 @@ class SymbolPredicate {
       }
     };
     
    +class KlassUsedPredicate {
    +  bool _current_epoch;
    +public:
    +  KlassUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
    +  bool operator()(const Klass* klass) {
    +    return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass);
    +  }
    +};
    +
     class MethodUsedPredicate {
       bool _current_epoch;
     public:
       MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
       bool operator()(const Klass* klass) {
    +    if (!klass->is_instance_klass()) {
    +      return false;
    +    }
         return _current_epoch ? METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_PREVIOUS_EPOCH(klass);
       }
     };
    @@ -210,7 +200,10 @@ class JfrArtifactSet : public JfrCHeapObj {
       JfrSymbolTable* _symbol_table;
       GrowableArray* _klass_list;
       GrowableArray* _klass_loader_set;
    +  GrowableArray* _klass_loader_leakp_set;
    +  GrowableArray* _unloading_set;
       size_t _total_count;
    +  bool _class_unload;
     
      public:
       JfrArtifactSet(bool class_unload);
    @@ -235,14 +228,20 @@ class JfrArtifactSet : public JfrCHeapObj {
       int entries() const;
       size_t total_count() const;
       void register_klass(const Klass* k);
    -  bool should_do_loader_klass(const Klass* k);
    +  bool should_do_cld_klass(const Klass* k, bool leakp);
    +  bool should_do_unloading_artifact(const void* ptr);
       void increment_checkpoint_id();
     
       template 
       void iterate_klasses(Functor& functor) const {
         for (int i = 0; i < _klass_list->length(); ++i) {
           if (!functor(_klass_list->at(i))) {
    -        break;
    +        return;
    +      }
    +    }
    +    for (int i = 0; i < _klass_loader_set->length(); ++i) {
    +      if (!functor(_klass_loader_set->at(i))) {
    +        return;
           }
         }
       }
    diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp
    index e5b9a33ef56..13853e14a13 100644
    --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp
    +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp
    @@ -33,6 +33,7 @@
     #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
     #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
     #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
    +#include "jfr/support/jfrKlassExtension.hpp"
     #include "oops/klass.hpp"
     #include "oops/method.hpp"
     #include "runtime/javaThread.hpp"
    @@ -66,10 +67,14 @@ inline traceid set_used_and_get(const T* type) {
       return TRACE_ID(type);
     }
     
    +// We set the 'method_and_class' bits to have a consistent
    +// bit pattern set always. This is because the tag is non-atomic,
    +// hence, we always need the same bit pattern in an epoch to avoid losing information.
     inline void JfrTraceIdLoadBarrier::load_barrier(const Klass* klass) {
    -    SET_USED_THIS_EPOCH(klass);
    -    enqueue(klass);
    -    JfrTraceIdEpoch::set_changed_tag_state();
    +  SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass);
    +  assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
    +  enqueue(klass);
    +  JfrTraceIdEpoch::set_changed_tag_state();
     }
     
     inline traceid JfrTraceIdLoadBarrier::load(const Klass* klass) {
    @@ -113,26 +118,36 @@ inline traceid JfrTraceIdLoadBarrier::load_no_enqueue(const Klass* klass, const
       return (METHOD_ID(klass, method));
     }
     
    -inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) {
    -  return set_used_and_get(module);
    -}
    -
    -inline traceid JfrTraceIdLoadBarrier::load(const PackageEntry* package) {
    -  return set_used_and_get(package);
    -}
    -
     inline traceid JfrTraceIdLoadBarrier::load(const ClassLoaderData* cld) {
       assert(cld != nullptr, "invariant");
       if (cld->has_class_mirror_holder()) {
         return 0;
       }
       const Klass* const class_loader_klass = cld->class_loader_klass();
    -  if (class_loader_klass != nullptr && should_tag(class_loader_klass)) {
    -    load_barrier(class_loader_klass);
    +  if (class_loader_klass != nullptr) {
    +    load(class_loader_klass);
       }
       return set_used_and_get(cld);
     }
     
    +inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) {
    +  assert(module != nullptr, "invariant");
    +  const ClassLoaderData* cld = module->loader_data();
    +  if (cld != nullptr) {
    +    load(cld);
    +  }
    +  return set_used_and_get(module);
    +}
    +
    +inline traceid JfrTraceIdLoadBarrier::load(const PackageEntry* package) {
    +  assert(package != nullptr, "invariant");
    +  const ModuleEntry* const module_entry = package->module();
    +  if (module_entry != nullptr) {
    +    load(module_entry);
    +  }
    +  return set_used_and_get(package);
    +}
    +
     inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Method* method) {
       assert(klass != nullptr, "invariant");
       assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
    diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
    index 40c3d7a8c4f..cc460f8c2aa 100644
    --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
    +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
    @@ -86,9 +86,6 @@ bool JfrRecorder::create_oop_storages() {
       return ObjectSampler::create_oop_storage();
     }
     
    -// Subsystem
    -static JfrCheckpointManager* _checkpoint_manager = nullptr;
    -
     bool JfrRecorder::on_create_vm_1() {
       if (!is_disabled()) {
         if (FlightRecorder || is_started_on_commandline()) {
    @@ -99,9 +96,10 @@ bool JfrRecorder::on_create_vm_1() {
         return false;
       }
     
    -  _checkpoint_manager = JfrCheckpointManager::create();
    -  if (_checkpoint_manager == nullptr || !_checkpoint_manager->initialize_early()) {
    -    return false;
    +  if (is_started_on_commandline()) {
    +    if (!create_checkpoint_manager()) {
    +      return false;
    +    }
       }
     
       // fast time initialization
    @@ -292,7 +290,7 @@ bool JfrRecorder::create_components() {
       if (!create_storage()) {
         return false;
       }
    -  if (!create_checkpoint_manager()) {
    +  if (!initialize_checkpoint_manager()) {
         return false;
       }
       if (!create_stacktrace_repository()) {
    @@ -321,6 +319,7 @@ static JfrStackTraceRepository* _stack_trace_repository;
     static JfrStringPool* _stringpool = nullptr;
     static JfrOSInterface* _os_interface = nullptr;
     static JfrThreadSampling* _thread_sampling = nullptr;
    +static JfrCheckpointManager* _checkpoint_manager = nullptr;
     
     bool JfrRecorder::create_java_event_writer() {
       return JfrJavaEventWriter::initialize();
    @@ -357,6 +356,17 @@ bool JfrRecorder::create_storage() {
     }
     
     bool JfrRecorder::create_checkpoint_manager() {
    +  assert(_checkpoint_manager == nullptr, "invariant");
    +  _checkpoint_manager = JfrCheckpointManager::create();
    +  return _checkpoint_manager != nullptr && _checkpoint_manager->initialize_early();
    +}
    +
    +bool JfrRecorder::initialize_checkpoint_manager() {
    +  if (_checkpoint_manager == nullptr) {
    +    if (!create_checkpoint_manager()) {
    +      return false;
    +    }
    +  }
       assert(_checkpoint_manager != nullptr, "invariant");
       assert(_repository != nullptr, "invariant");
       return _checkpoint_manager->initialize(&_repository->chunkwriter());
    diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp
    index 3e2541fad98..9f4969b0187 100644
    --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp
    +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp
    @@ -42,6 +42,7 @@ class JfrRecorder : public JfrCHeapObj {
       static bool on_create_vm_2();
       static bool on_create_vm_3();
       static bool create_checkpoint_manager();
    +  static bool initialize_checkpoint_manager();
       static bool create_chunk_repository();
       static bool create_java_event_writer();
       static bool create_jvmti_agent();
    diff --git a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp
    index 09a452caaa5..49ced300e55 100644
    --- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp
    +++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp
    @@ -626,8 +626,8 @@ inline bool ReinitializeAllReleaseRetiredOp::process(typename
       const bool retired = node->retired();
       node->reinitialize();
       assert(node->empty(), "invariant");
    -  assert(!node->retired(), "invariant");
       if (retired) {
    +    assert(!node->retired(), "invariant");
         _prev = _list.excise(_prev, node);
         node->release();
         mspace_release(node, _mspace);
    diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp
    index a36b85dbb7e..5f5c87d239c 100644
    --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp
    +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp
    @@ -371,8 +371,10 @@ void JfrDeprecationManager::write_edges(JfrChunkWriter& cw, Thread* thread, bool
     
     void JfrDeprecationManager::on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread) {
       assert(_pending_list.is_empty(), "invariant");
    -  if (writer.has_data() && _pending_head != nullptr) {
    +  if (_pending_head != nullptr) {
         save_type_set_blob(writer);
    +  } else {
    +    writer.cancel();
       }
       if (cw != nullptr) {
         write_edges(*cw, thread);
    diff --git a/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp
    index c26592763d4..e4c3a43c3b9 100644
    --- a/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp
    +++ b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp
    @@ -69,7 +69,7 @@ static inline JfrTicksWrapper* allocate_start_time() {
       return EventType::is_enabled() ? new JfrTicksWrapper() : nullptr;
     }
     
    -NativeLibraryLoadEvent::NativeLibraryLoadEvent(const char* name, void** result) : JfrNativeLibraryEventBase(name), _result(result) {
    +NativeLibraryLoadEvent::NativeLibraryLoadEvent(const char* name, void** result) : JfrNativeLibraryEventBase(name), _result(result), _fp_env_correction_attempt(false), _fp_env_correction_success(false) {
       assert(_result != nullptr, "invariant");
       _start_time = allocate_start_time();
     }
    @@ -90,8 +90,17 @@ void NativeLibraryUnloadEvent::set_result(bool result) {
       _result = result;
     }
     
    +static void set_additional_data(EventNativeLibraryLoad& event, const NativeLibraryLoadEvent& helper) {
    +  event.set_fpEnvCorrectionAttempt(helper.get_fp_env_correction_attempt());
    +  event.set_fpEnvCorrectionSuccess(helper.get_fp_env_correction_success());
    +}
    +
    +static void set_additional_data(EventNativeLibraryUnload& event, const NativeLibraryUnloadEvent& helper) {
    +  // no additional entries atm. for the unload event
    +}
    +
     template 
    -static void commit(HelperType& helper) {
    +static void commit(const HelperType& helper) {
       if (!helper.has_start_time()) {
         return;
       }
    @@ -101,17 +110,20 @@ static void commit(HelperType& helper) {
       event.set_name(helper.name());
       event.set_errorMessage(helper.error_msg());
       event.set_success(helper.success());
    +  set_additional_data(event, helper);
       Thread* thread = Thread::current();
       assert(thread != nullptr, "invariant");
       if (thread->is_Java_thread()) {
         JavaThread* jt = JavaThread::cast(thread);
    -    if (jt->thread_state() != _thread_in_vm) {
    -      assert(jt->thread_state() == _thread_in_native, "invariant");
    +    if (jt->thread_state() == _thread_in_native) {
           // For a JavaThread to take a JFR stacktrace, it must be in _thread_in_vm. Can safepoint here.
           ThreadInVMfromNative transition(jt);
           event.commit();
           return;
         }
    +    // If a thread comes here still _thread_in_Java, which can happen for example
    +    // when loading the disassembler library in response to traps in JIT code - all is ok.
    +    // Since there is no ljf, an event will be committed without a stacktrace.
       }
       event.commit();
     }
    diff --git a/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp
    index fe8431fdc43..30281ad4d05 100644
    --- a/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp
    +++ b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp
    @@ -52,10 +52,16 @@ class JfrNativeLibraryEventBase : public StackObj {
     class NativeLibraryLoadEvent : public JfrNativeLibraryEventBase {
      private:
       void** _result;
    +  bool _fp_env_correction_attempt;
    +  bool _fp_env_correction_success;
      public:
       NativeLibraryLoadEvent(const char* name, void** result);
       ~NativeLibraryLoadEvent();
       bool success() const;
    +  bool get_fp_env_correction_attempt() const { return _fp_env_correction_attempt; }
    +  bool get_fp_env_correction_success() const { return _fp_env_correction_success; }
    +  void set_fp_env_correction_attempt(bool v) { _fp_env_correction_attempt = v; }
    +  void set_fp_env_correction_success(bool v) { _fp_env_correction_success = v; }
     };
     
     class NativeLibraryUnloadEvent : public JfrNativeLibraryEventBase {
    diff --git a/src/hotspot/share/jfr/utilities/jfrVersionSystem.hpp b/src/hotspot/share/jfr/utilities/jfrVersionSystem.hpp
    index 5005b5b8f3f..39c40fd7147 100644
    --- a/src/hotspot/share/jfr/utilities/jfrVersionSystem.hpp
    +++ b/src/hotspot/share/jfr/utilities/jfrVersionSystem.hpp
    @@ -105,9 +105,9 @@ class JfrVersionSystem : public JfrCHeapObj {
       NodePtr synchronize_with(Type version, NodePtr last) const;
       DEBUG_ONLY(void assert_state(const Node* node) const;)
       struct PaddedTip {
    -    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
         volatile Type _value;
    -    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile Type));
    +    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(volatile Type));
       };
       PaddedTip _tip;
       NodePtr _head;
    diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp
    index 421ebd7396f..ff159a490c1 100644
    --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp
    +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp
    @@ -115,6 +115,13 @@ class CompilerToVM {
         // Minimum alignment of an offset into CodeBuffer::SECT_CONSTS
         static int data_section_item_alignment;
     
    +    /*
    +     * Pointer to JvmtiExport::_should_notify_object_alloc.
    +     * Exposed as an int* instead of an address so the
    +     * underlying type is part of the JVMCIVMStructs definition.
    +     */
    +    static int* _should_notify_object_alloc;
    +
        public:
          static void initialize(JVMCI_TRAPS);
     
    diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
    index a3e2bd525ec..89fa78b10f3 100644
    --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
    +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
    @@ -45,6 +45,7 @@
     #include "memory/universe.hpp"
     #include "oops/compressedOops.hpp"
     #include "oops/klass.inline.hpp"
    +#include "prims/jvmtiExport.hpp"
     #ifdef COMPILER2
     #include "opto/c2compiler.hpp"
     #endif
    @@ -130,6 +131,8 @@ address CompilerToVM::Data::symbol_clinit;
     
     int CompilerToVM::Data::data_section_item_alignment;
     
    +int* CompilerToVM::Data::_should_notify_object_alloc;
    +
     void CompilerToVM::Data::initialize(JVMCI_TRAPS) {
       Klass_vtable_start_offset = in_bytes(Klass::vtable_start_offset());
       Klass_vtable_length_offset = in_bytes(Klass::vtable_length_offset());
    @@ -196,6 +199,8 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) {
     
       data_section_item_alignment = relocInfo::addr_unit();
     
    +  _should_notify_object_alloc = &JvmtiExport::_should_notify_object_alloc;
    +
       BarrierSet* bs = BarrierSet::barrier_set();
       if (bs->is_a(BarrierSet::CardTableBarrierSet)) {
         CardTable::CardValue* base = ci_card_table_address();
    diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
    index 0c389efdd0f..daa3bacf81c 100644
    --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
    +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
    @@ -122,6 +122,8 @@
                                                                                                                                          \
       static_field(CompilerToVM::Data,             data_section_item_alignment,            int)                                          \
                                                                                                                                          \
    +  static_field(CompilerToVM::Data,             _should_notify_object_alloc,            int*)                                         \
    +                                                                                                                                     \
       static_field(Abstract_VM_Version,            _features,                              uint64_t)                                     \
                                                                                                                                          \
       nonstatic_field(Annotations,                 _class_annotations,                     AnnotationArray*)                             \
    @@ -220,6 +222,7 @@
       nonstatic_field(JavaThread,                  _lock_stack,                                   LockStack)                             \
       JVMTI_ONLY(nonstatic_field(JavaThread,       _is_in_VTMS_transition,                        bool))                                 \
       JVMTI_ONLY(nonstatic_field(JavaThread,       _is_in_tmp_VTMS_transition,                    bool))                                 \
    +  JVMTI_ONLY(nonstatic_field(JavaThread,       _is_disable_suspend,                           bool))                                 \
                                                                                                                                          \
       nonstatic_field(LockStack,                   _top,                                          uint32_t)                              \
                                                                                                                                          \
    diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp
    index cf6dc58eb46..ed6066bc1db 100644
    --- a/src/hotspot/share/logging/logTag.hpp
    +++ b/src/hotspot/share/logging/logTag.hpp
    @@ -97,6 +97,7 @@ class outputStream;
       LOG_TAG(iklass) \
       LOG_TAG(indy) \
       LOG_TAG(init) \
    +  LOG_TAG(inlinecache)\
       LOG_TAG(inlining) \
       LOG_TAG(install) \
       LOG_TAG(interpreter) \
    diff --git a/src/hotspot/share/memory/padded.hpp b/src/hotspot/share/memory/padded.hpp
    index 1811810c19e..0597dbd9f3c 100644
    --- a/src/hotspot/share/memory/padded.hpp
    +++ b/src/hotspot/share/memory/padded.hpp
    @@ -40,14 +40,14 @@
     // effective only when applied to derived-most (leaf) classes.
     
     // When no args are passed to the base ctor.
    -template 
    +template 
     class Padded : public T {
      private:
       char _pad_buf_[PADDING_SIZE(T, alignment)];
     };
     
     // When either 0 or 1 args may be passed to the base ctor.
    -template 
    +template 
     class Padded01 : public T {
      public:
       Padded01(): T() { }
    @@ -75,7 +75,7 @@ class PaddedEndImpl : public T {
     // minimal amount of padding needed to make the size of the objects be aligned.
     // This will help reducing false sharing,
     // if the start address is a multiple of alignment.
    -template 
    +template 
     class PaddedEnd : public PaddedEndImpl {
       // C++ doesn't allow zero-length arrays. The padding is put in a
       // super class that is specialized for the pad_size == 0 case.
    @@ -89,7 +89,7 @@ class PaddedEnd : public PaddedEndImpl {
     
     // Helper class to create an array of PaddedEnd objects. All elements will
     // start at a multiple of alignment and the size will be aligned to alignment.
    -template 
    +template 
     class PaddedArray {
      public:
       // Creates an aligned padded array.
    @@ -100,7 +100,7 @@ class PaddedArray {
     // Helper class to create an array of references to arrays of primitive types
     // Both the array of references and the data arrays are aligned to the given
     // alignment. The allocated memory is zero-filled.
    -template 
    +template 
     class Padded2DArray {
      public:
       // Creates an aligned padded 2D array.
    @@ -112,7 +112,7 @@ class Padded2DArray {
     
     // Helper class to create an array of T objects. The array as a whole will
     // start at a multiple of alignment and its size will be aligned to alignment.
    -template 
    +template 
     class PaddedPrimitiveArray {
      public:
       static T* create_unfreeable(size_t length);
    diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp
    index 9a8d5faf840..8b31053b5d6 100644
    --- a/src/hotspot/share/memory/universe.cpp
    +++ b/src/hotspot/share/memory/universe.cpp
    @@ -344,7 +344,7 @@ void Universe::genesis(TRAPS) {
           // Initialization of the fillerArrayKlass must come before regular
           // int-TypeArrayKlass so that the int-Array mirror points to the
           // int-TypeArrayKlass.
    -      _fillerArrayKlassObj = TypeArrayKlass::create_klass(T_INT, "Ljdk/internal/vm/FillerArray;", CHECK);
    +      _fillerArrayKlassObj = TypeArrayKlass::create_klass(T_INT, "[Ljdk/internal/vm/FillerElement;", CHECK);
           for (int i = T_BOOLEAN; i < T_LONG+1; i++) {
             _typeArrayKlassObjs[i] = TypeArrayKlass::create_klass((BasicType)i, CHECK);
           }
    diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp
    index 3d1816ab630..a7a8b98688e 100644
    --- a/src/hotspot/share/nmt/mallocTracker.cpp
    +++ b/src/hotspot/share/nmt/mallocTracker.cpp
    @@ -59,6 +59,23 @@ void MemoryCounter::update_peak(size_t size, size_t cnt) {
       }
     }
     
    +void MallocMemorySnapshot::copy_to(MallocMemorySnapshot* s) {
    +  // Use ThreadCritical to make sure that mtChunks don't get deallocated while the
    +  // copy is going on, because their size is adjusted using this
    +  // buffer in make_adjustment().
    +  ThreadCritical tc;
    +  s->_all_mallocs = _all_mallocs;
    +  size_t total_size = 0;
    +  size_t total_count = 0;
    +  for (int index = 0; index < mt_number_of_types; index ++) {
    +    s->_malloc[index] = _malloc[index];
    +    total_size += s->_malloc[index].malloc_size();
    +    total_count += s->_malloc[index].malloc_count();
    +  }
    +  // malloc counters may be updated concurrently
    +  s->_all_mallocs.set_size_and_count(total_size, total_count);
    +}
    +
     // Total malloc'd memory used by arenas
     size_t MallocMemorySnapshot::total_arena() const {
       size_t amount = 0;
    diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp
    index 964acb6d201..f3b38b43ef0 100644
    --- a/src/hotspot/share/nmt/mallocTracker.hpp
    +++ b/src/hotspot/share/nmt/mallocTracker.hpp
    @@ -55,6 +55,12 @@ class MemoryCounter {
      public:
       MemoryCounter() : _count(0), _size(0), _peak_count(0), _peak_size(0) {}
     
    +  inline void set_size_and_count(size_t size, size_t count) {
    +    _size = size;
    +    _count = count;
    +    update_peak(size, count);
    +  }
    +
       inline void allocate(size_t sz) {
         size_t cnt = Atomic::add(&_count, size_t(1), memory_order_relaxed);
         if (sz > 0) {
    @@ -176,16 +182,7 @@ class MallocMemorySnapshot {
       // Total malloc'd memory used by arenas
       size_t total_arena() const;
     
    -  void copy_to(MallocMemorySnapshot* s) {
    -     // Need to make sure that mtChunks don't get deallocated while the
    -     // copy is going on, because their size is adjusted using this
    -     // buffer in make_adjustment().
    -     ThreadCritical tc;
    -     s->_all_mallocs = _all_mallocs;
    -     for (int index = 0; index < mt_number_of_types; index ++) {
    -       s->_malloc[index] = _malloc[index];
    -     }
    -   }
    +  void copy_to(MallocMemorySnapshot* s);
     
       // Make adjustment by subtracting chunks used by arenas
       // from total chunks to get total free chunk size
    diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp
    index 16fbaa30276..471c9eafd0e 100644
    --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp
    +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp
    @@ -399,12 +399,16 @@ bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size,
           }
     
           // Print some more details. Don't use UL here to avoid circularities.
    -#ifdef ASSERT
           tty->print_cr("Error: existing region: [" INTPTR_FORMAT "-" INTPTR_FORMAT "), flag %u.\n"
                         "       new region: [" INTPTR_FORMAT "-" INTPTR_FORMAT "), flag %u.",
                         p2i(reserved_rgn->base()), p2i(reserved_rgn->end()), (unsigned)reserved_rgn->flag(),
                         p2i(base_addr), p2i(base_addr + size), (unsigned)flag);
    -#endif
    +      if (MemTracker::tracking_level() == NMT_detail) {
    +        tty->print_cr("Existing region allocated from:");
    +        reserved_rgn->call_stack()->print_on(tty);
    +        tty->print_cr("New region allocated from:");
    +        stack.print_on(tty);
    +      }
           ShouldNotReachHere();
           return false;
         }
    @@ -479,7 +483,7 @@ bool VirtualMemoryTracker::remove_released_region(ReservedMemoryRegion* rgn) {
     
       VirtualMemorySummary::record_released_memory(rgn->size(), rgn->flag());
       result =  _reserved_regions->remove(*rgn);
    -  log_debug(nmt)("Removed region \'%s\' (" INTPTR_FORMAT ", " SIZE_FORMAT ") from _resvered_regions %s" ,
    +  log_debug(nmt)("Removed region \'%s\' (" INTPTR_FORMAT ", " SIZE_FORMAT ") from _reserved_regions %s" ,
                     backup.flag_name(), p2i(backup.base()), backup.size(), (result ? "Succeeded" : "Failed"));
       return result;
     }
    diff --git a/src/hotspot/share/oops/access.hpp b/src/hotspot/share/oops/access.hpp
    index 8cc5782c5ba..d840c828ab4 100644
    --- a/src/hotspot/share/oops/access.hpp
    +++ b/src/hotspot/share/oops/access.hpp
    @@ -53,8 +53,8 @@
     // * store_at: Store a value in an internal pointer relative to a base object.
     // * atomic_cmpxchg: Atomically compare-and-swap a new value at an address if previous value matched the compared value.
     // * atomic_cmpxchg_at: Atomically compare-and-swap a new value at an internal pointer address if previous value matched the compared value.
    -// * atomic_xchg: Atomically swap a new value at an address if previous value matched the compared value.
    -// * atomic_xchg_at: Atomically swap a new value at an internal pointer address if previous value matched the compared value.
    +// * atomic_xchg: Atomically swap a new value at an address without checking the previous value.
    +// * atomic_xchg_at: Atomically swap a new value at an internal pointer address without checking the previous value.
     // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this.
     // * clone: Clone the contents of an object to a newly allocated object.
     // * value_copy: Copy the contents of a value type from one heap address to another
    @@ -84,12 +84,11 @@
     //             and whether the access is performed on the heap or outside. Then the
     //             appropriate BarrierSet::AccessBarrier is called to perform the access.
     //
    -// The implementation of step 1-4 resides in in accessBackend.hpp, to allow selected
    +// The implementation of step 1-4 resides in accessBackend.hpp, to allow selected
     // accesses to be accessible from only access.hpp, as opposed to access.inline.hpp.
     // Steps 5.a and 5.b require knowledge about the GC backends, and therefore needs to
     // include the various GC backend .inline.hpp headers. Their implementation resides in
    -// access.inline.hpp. The accesses that are allowed through the access.hpp file
    -// must be instantiated in access.cpp using the INSTANTIATE_HPP_ACCESS macro.
    +// access.inline.hpp.
     
     class InlineKlass;
     
    diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp
    index 926b93382c5..d610cef7718 100644
    --- a/src/hotspot/share/oops/constantPool.hpp
    +++ b/src/hotspot/share/oops/constantPool.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -539,7 +539,7 @@ class ConstantPool : public Metadata {
         int offset = build_int_from_shorts(operands->at(n+0),
                                            operands->at(n+1));
         // The offset itself must point into the second part of the array.
    -    assert(offset == 0 || offset >= second_part && offset <= operands->length(), "oob (3)");
    +    assert(offset == 0 || (offset >= second_part && offset <= operands->length()), "oob (3)");
         return offset;
       }
       static void operand_offset_at_put(Array* operands, int bsms_attribute_index, int offset) {
    diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp
    index 22fdfbf7af0..6bd11f1225e 100644
    --- a/src/hotspot/share/oops/method.cpp
    +++ b/src/hotspot/share/oops/method.cpp
    @@ -336,7 +336,7 @@ int Method::bci_from(address bcp) const {
       }
       // Do not have a ResourceMark here because AsyncGetCallTrace stack walking code
       // may call this after interrupting a nested ResourceMark.
    -  assert(is_native() && bcp == code_base() || contains(bcp) || VMError::is_error_reported(),
    +  assert((is_native() && bcp == code_base()) || contains(bcp) || VMError::is_error_reported(),
              "bcp doesn't belong to this method. bcp: " PTR_FORMAT, p2i(bcp));
     
       return int(bcp - code_base());
    @@ -370,7 +370,7 @@ address Method::bcp_from(int bci) const {
       assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()),
              "illegal bci: %d for %s method", bci, is_native() ? "native" : "non-native");
       address bcp = code_base() + bci;
    -  assert(is_native() && bcp == code_base() || contains(bcp), "bcp doesn't belong to this method");
    +  assert((is_native() && bcp == code_base()) || contains(bcp), "bcp doesn't belong to this method");
       return bcp;
     }
     
    diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp
    index 2ace6a99040..80f659b0055 100644
    --- a/src/hotspot/share/oops/method.hpp
    +++ b/src/hotspot/share/oops/method.hpp
    @@ -409,7 +409,8 @@ class Method : public Metadata {
       void remove_unshareable_flags() NOT_CDS_RETURN;
     
       // the number of argument reg slots that the compiled method uses on the stack.
    -  int num_stack_arg_slots() const { return constMethod()->num_stack_arg_slots(); }
    +  int num_stack_arg_slots(bool rounded = true) const {
    +    return rounded ? align_up(constMethod()->num_stack_arg_slots(), 2) : constMethod()->num_stack_arg_slots(); }
     
       virtual void metaspace_pointers_do(MetaspaceClosure* iter);
       virtual MetaspaceObj::Type type() const { return MethodType; }
    diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp
    index 851eb79e1e2..3139828cf27 100644
    --- a/src/hotspot/share/oops/oop.hpp
    +++ b/src/hotspot/share/oops/oop.hpp
    @@ -55,8 +55,6 @@
     
     // Forward declarations.
     class OopClosure;
    -class FilteringClosure;
    -
     class PSPromotionManager;
     class ParCompactionManager;
     
    diff --git a/src/hotspot/share/oops/stackChunkOop.hpp b/src/hotspot/share/oops/stackChunkOop.hpp
    index 36b06ecd324..abfe47ad3f1 100644
    --- a/src/hotspot/share/oops/stackChunkOop.hpp
    +++ b/src/hotspot/share/oops/stackChunkOop.hpp
    @@ -155,7 +155,7 @@ class stackChunkOopDesc : public instanceOopDesc {
     
       inline void* gc_data() const;
       inline BitMapView bitmap() const;
    -  inline BitMap::idx_t bit_index_for(intptr_t* p) const;
    +  inline BitMap::idx_t bit_index_for(address p) const;
       inline intptr_t* address_for_bit(BitMap::idx_t index) const;
       template  inline BitMap::idx_t bit_index_for(OopT* p) const;
       template  inline OopT* address_for_bit(BitMap::idx_t index) const;
    diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp
    index e1993207266..c7590861032 100644
    --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp
    +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp
    @@ -256,12 +256,13 @@ inline BitMapView stackChunkOopDesc::bitmap() const {
       return bitmap;
     }
     
    -inline BitMap::idx_t stackChunkOopDesc::bit_index_for(intptr_t* p) const {
    +inline BitMap::idx_t stackChunkOopDesc::bit_index_for(address p) const {
       return UseCompressedOops ? bit_index_for((narrowOop*)p) : bit_index_for((oop*)p);
     }
     
     template 
     inline BitMap::idx_t stackChunkOopDesc::bit_index_for(OopT* p) const {
    +  assert(is_aligned(p, alignof(OopT)), "should be aligned: " PTR_FORMAT, p2i(p));
       assert(p >= (OopT*)start_address(), "Address not in chunk");
       return p - (OopT*)start_address();
     }
    diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp
    index db8f6f19548..30c2d24c42d 100644
    --- a/src/hotspot/share/opto/addnode.cpp
    +++ b/src/hotspot/share/opto/addnode.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -253,6 +253,22 @@ AddNode* AddNode::make(Node* in1, Node* in2, BasicType bt) {
       return nullptr;
     }
     
    +bool AddNode::is_not(PhaseGVN* phase, Node* n, BasicType bt) {
    +  return n->Opcode() == Op_Xor(bt) && phase->type(n->in(2)) == TypeInteger::minus_1(bt);
    +}
    +
    +AddNode* AddNode::make_not(PhaseGVN* phase, Node* n, BasicType bt) {
    +  switch (bt) {
    +    case T_INT:
    +      return new XorINode(n, phase->intcon(-1));
    +    case T_LONG:
    +      return new XorLNode(n, phase->longcon(-1L));
    +    default:
    +      fatal("Not implemented for %s", type2name(bt));
    +  }
    +  return nullptr;
    +}
    +
     //=============================================================================
     //------------------------------Idealize---------------------------------------
     Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) {
    diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp
    index 709958b6abf..577dd6ba295 100644
    --- a/src/hotspot/share/opto/addnode.hpp
    +++ b/src/hotspot/share/opto/addnode.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -78,6 +78,13 @@ class AddNode : public Node {
       virtual int min_opcode() const = 0;
     
       static AddNode* make(Node* in1, Node* in2, BasicType bt);
    +
    +  // Utility function to check if the given node is a NOT operation,
    +  // i.e., n == m ^ (-1).
    +  static bool is_not(PhaseGVN* phase, Node* n, BasicType bt);
    +
    +  // Utility function to make a NOT operation, i.e., returning n ^ (-1).
    +  static AddNode* make_not(PhaseGVN* phase, Node* n, BasicType bt);
     };
     
     //------------------------------AddINode---------------------------------------
    diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp
    index 2617d1b5033..202f6c5eb8a 100644
    --- a/src/hotspot/share/opto/c2_globals.hpp
    +++ b/src/hotspot/share/opto/c2_globals.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -93,6 +93,10 @@
       product(bool, AlignVector, true,                                          \
               "Perform vector store/load alignment in loop")                    \
                                                                                 \
    +  develop(bool, VerifyAlignVector, false,                                   \
    +          "Check that vector stores/loads are aligned if AlignVector"       \
    +          "is enabled.")                                                    \
    +                                                                            \
       product(intx, NumberOfLoopInstrToAlign, 4,                                \
               "Number of first instructions in a loop to align")                \
               range(0, max_jint)                                                \
    @@ -365,10 +369,10 @@
               "Level of detail of the ideal graph printout. "                   \
               "System-wide value, -1=printing is disabled, "                    \
               "0=print nothing except IGVPrintLevel directives, "               \
    -          "5=all details printed. "                                         \
    +          "6=all details printed. "                                         \
               "Level of detail of printouts can be set on a per-method level "  \
               "as well by using CompileCommand=option.")                        \
    -          range(-1, 5)                                                      \
    +          range(-1, 6)                                                      \
                                                                                 \
       notproduct(intx, PrintIdealGraphPort, 4444,                               \
               "Ideal graph printer to network port")                            \
    diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp
    index 51b923e46f0..0d0266e86f0 100644
    --- a/src/hotspot/share/opto/c2compiler.cpp
    +++ b/src/hotspot/share/opto/c2compiler.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -34,6 +34,7 @@
     #include "opto/output.hpp"
     #include "opto/runtime.hpp"
     #include "runtime/stubRoutines.hpp"
    +#include "runtime/globals_extension.hpp"
     #include "utilities/macros.hpp"
     
     
    @@ -64,6 +65,13 @@ void compiler_stubs_init(bool in_compiler_thread);
     
     bool C2Compiler::init_c2_runtime() {
     
    +#ifdef ASSERT
    +  if (!AlignVector && VerifyAlignVector) {
    +    warning("VerifyAlignVector disabled because AlignVector is not enabled.");
    +    FLAG_SET_CMDLINE(VerifyAlignVector, false);
    +  }
    +#endif
    +
       // Check assumptions used while running ADLC
       Compile::adlc_verification();
       assert(REG_COUNT <= ConcreteRegisterImpl::number_of_registers, "incompatible register counts");
    @@ -829,6 +837,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
       case vmIntrinsics::_notifyJvmtiVThreadMount:
       case vmIntrinsics::_notifyJvmtiVThreadUnmount:
       case vmIntrinsics::_notifyJvmtiVThreadHideFrames:
    +  case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend:
     #endif
         break;
     
    diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
    index f322235b7d2..46abd4cec5e 100644
    --- a/src/hotspot/share/opto/callnode.cpp
    +++ b/src/hotspot/share/opto/callnode.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1021,8 +1021,8 @@ Node* CallNode::Ideal(PhaseGVN* phase, bool can_reshape) {
       // Validate attached generator
       CallGenerator* cg = generator();
       if (cg != nullptr) {
    -    assert(is_CallStaticJava()  && cg->is_mh_late_inline() ||
    -           is_CallDynamicJava() && cg->is_virtual_late_inline(), "mismatch");
    +    assert((is_CallStaticJava()  && cg->is_mh_late_inline()) ||
    +           (is_CallDynamicJava() && cg->is_virtual_late_inline()), "mismatch");
       }
     #endif // ASSERT
       return SafePointNode::Ideal(phase, can_reshape);
    @@ -1859,8 +1859,8 @@ Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseValu
           //   - the narrow_length is 0
           //   - the narrow_length is not wider than length
           assert(narrow_length_type == TypeInt::ZERO ||
    -             length_type->is_con() && narrow_length_type->is_con() &&
    -                (narrow_length_type->_hi <= length_type->_lo) ||
    +             (length_type->is_con() && narrow_length_type->is_con() &&
    +              (narrow_length_type->_hi <= length_type->_lo)) ||
                  (narrow_length_type->_hi <= length_type->_hi &&
                   narrow_length_type->_lo >= length_type->_lo),
                  "narrow type must be narrower than length type");
    @@ -1873,8 +1873,7 @@ Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseValu
           // propagate the fact that the array length must be positive.
           InitializeNode* init = initialization();
           if (init != nullptr) {
    -        length = new CastIINode(length, narrow_length_type);
    -        length->set_req(TypeFunc::Control, init->proj_out_or_null(TypeFunc::Control));
    +        length = new CastIINode(init->proj_out_or_null(TypeFunc::Control), length, narrow_length_type);
           }
         }
       }
    diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp
    index 63b7cfa76cc..28492010734 100644
    --- a/src/hotspot/share/opto/castnode.cpp
    +++ b/src/hotspot/share/opto/castnode.cpp
    @@ -144,54 +144,12 @@ uint ConstraintCastNode::size_of() const {
       return sizeof(*this);
     }
     
    -Node* ConstraintCastNode::make_cast(int opcode, Node* c, Node* n, const Type* t, DependencyType dependency,
    -                                    const TypeTuple* extra_types) {
    -  switch(opcode) {
    -  case Op_CastII: {
    -    Node* cast = new CastIINode(n, t, dependency, false, extra_types);
    -    cast->set_req(0, c);
    -    return cast;
    -  }
    -  case Op_CastLL: {
    -    Node* cast = new CastLLNode(n, t, dependency, extra_types);
    -    cast->set_req(0, c);
    -    return cast;
    -  }
    -  case Op_CastPP: {
    -    Node* cast = new CastPPNode(n, t, dependency, extra_types);
    -    cast->set_req(0, c);
    -    return cast;
    -  }
    -  case Op_CastFF: {
    -    Node* cast = new CastFFNode(n, t, dependency, extra_types);
    -    cast->set_req(0, c);
    -    return cast;
    -  }
    -  case Op_CastDD: {
    -    Node* cast = new CastDDNode(n, t, dependency, extra_types);
    -    cast->set_req(0, c);
    -    return cast;
    -  }
    -  case Op_CastVV: {
    -    Node* cast = new CastVVNode(n, t, dependency, extra_types);
    -    cast->set_req(0, c);
    -    return cast;
    -  }
    -  case Op_CheckCastPP: return new CheckCastPPNode(c, n, t, dependency, extra_types);
    -  default:
    -    fatal("Bad opcode %d", opcode);
    -  }
    -  return nullptr;
    -}
    -
    -Node* ConstraintCastNode::make(Node* c, Node *n, const Type *t, DependencyType dependency, BasicType bt) {
    +Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* t, DependencyType dependency, BasicType bt) {
       switch(bt) {
    -  case T_INT: {
    -    return make_cast(Op_CastII, c, n, t, dependency, nullptr);
    -  }
    -  case T_LONG: {
    -    return make_cast(Op_CastLL, c, n, t, dependency, nullptr);
    -  }
    +  case T_INT:
    +    return new CastIINode(c, n, t, dependency);
    +  case T_LONG:
    +    return new CastLLNode(c, n, t, dependency);
       default:
         fatal("Bad basic type %s", type2name(bt));
       }
    @@ -288,7 +246,7 @@ const Type* CastIINode::Value(PhaseGVN* phase) const {
     }
     
     static Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, Node* control, const TypeInteger* type, ConstraintCastNode::DependencyType dependency, BasicType bt) {
    -  Node* n = ConstraintCastNode::make(control, parent, type, dependency, bt);
    +  Node* n = ConstraintCastNode::make_cast_for_basic_type(control, parent, type, dependency, bt);
       Node* existing = igvn->hash_find_insert(n);
       if (existing != nullptr) {
         n->destruct(igvn);
    @@ -544,21 +502,20 @@ Node* CastP2XNode::Identity(PhaseGVN* phase) {
     
     Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency,
                                                  const TypeTuple* types) {
    -  Node* cast= nullptr;
       if (type->isa_int()) {
    -    cast = make_cast(Op_CastII, c, in, type, dependency, types);
    +    return new CastIINode(c, in, type, dependency, false, types);
       } else if (type->isa_long()) {
    -    cast = make_cast(Op_CastLL, c, in, type, dependency, types);
    +    return new CastLLNode(c, in, type, dependency, types);
       } else if (type->isa_float()) {
    -    cast = make_cast(Op_CastFF, c, in, type, dependency, types);
    +    return new CastFFNode(c, in, type, dependency, types);
       } else if (type->isa_double()) {
    -    cast = make_cast(Op_CastDD, c, in, type, dependency, types);
    +    return new CastDDNode(c, in, type, dependency, types);
       } else if (type->isa_vect()) {
    -    cast = make_cast(Op_CastVV, c, in, type, dependency, types);
    +    return new CastVVNode(c, in, type, dependency, types);
       } else if (type->isa_ptr()) {
    -    cast = make_cast(Op_CastPP, c, in, type, dependency, types);
    +    return new CastPPNode(c, in, type, dependency, types);
       }
    -  return cast;
    +  fatal("unreachable. Invalid cast type.");
     }
     
     Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) {
    diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp
    index 6b517743195..73ee5d81a40 100644
    --- a/src/hotspot/share/opto/castnode.hpp
    +++ b/src/hotspot/share/opto/castnode.hpp
    @@ -54,10 +54,11 @@ class ConstraintCastNode: public TypeNode {
       const TypeTuple* _extra_types;
     
       public:
    -  ConstraintCastNode(Node* n, const Type* t, ConstraintCastNode::DependencyType dependency,
    +  ConstraintCastNode(Node* ctrl, Node* n, const Type* t, ConstraintCastNode::DependencyType dependency,
                          const TypeTuple* extra_types)
               : TypeNode(t,2), _dependency(dependency), _extra_types(extra_types) {
         init_class_id(Class_ConstraintCast);
    +    init_req(0, ctrl);
         init_req(1, n);
       }
       virtual Node* Identity(PhaseGVN* phase);
    @@ -68,8 +69,7 @@ class ConstraintCastNode: public TypeNode {
       virtual bool depends_only_on_test() const { return _dependency == RegularDependency; }
       bool carry_dependency() const { return _dependency != RegularDependency; }
       TypeNode* dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const;
    -  static Node* make_cast(int opcode, Node* c, Node* n, const Type* t, DependencyType dependency, const TypeTuple* extra_types);
    -  static Node* make(Node* c, Node *n, const Type *t, DependencyType dependency, BasicType bt);
    +  static Node* make_cast_for_basic_type(Node* c, Node* n, const Type* t, DependencyType dependency, BasicType bt);
     
     #ifndef PRODUCT
       virtual void dump_spec(outputStream *st) const;
    @@ -102,13 +102,12 @@ class CastIINode: public ConstraintCastNode {
     
       public:
       CastIINode(Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false, const TypeTuple* types = nullptr)
    -    : ConstraintCastNode(n, t, dependency, types), _range_check_dependency(range_check_dependency) {
    +    : ConstraintCastNode(nullptr, n, t, dependency, types), _range_check_dependency(range_check_dependency) {
         init_class_id(Class_CastII);
       }
    -  CastIINode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false)
    -    : ConstraintCastNode(n, t, dependency, nullptr), _range_check_dependency(range_check_dependency) {
    +  CastIINode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false, const TypeTuple* types = nullptr)
    +    : ConstraintCastNode(ctrl, n, t, dependency, types), _range_check_dependency(range_check_dependency) {
         init_class_id(Class_CastII);
    -    init_req(0, ctrl);
       }
       virtual int Opcode() const;
       virtual uint ideal_reg() const { return Op_RegI; }
    @@ -131,13 +130,8 @@ class CastIINode: public ConstraintCastNode {
     
     class CastLLNode: public ConstraintCastNode {
     public:
    -  CastLLNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency)
    -    : ConstraintCastNode(n, t, dependency, nullptr) {
    -    init_class_id(Class_CastLL);
    -    init_req(0, ctrl);
    -  }
    -  CastLLNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    -          : ConstraintCastNode(n, t, dependency, types) {
    +  CastLLNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    +          : ConstraintCastNode(ctrl, n, t, dependency, types) {
         init_class_id(Class_CastLL);
       }
     
    @@ -149,8 +143,8 @@ class CastLLNode: public ConstraintCastNode {
     
     class CastFFNode: public ConstraintCastNode {
     public:
    -  CastFFNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    -          : ConstraintCastNode(n, t, dependency, types) {
    +  CastFFNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    +          : ConstraintCastNode(ctrl, n, t, dependency, types) {
         init_class_id(Class_CastFF);
       }
       virtual int Opcode() const;
    @@ -159,8 +153,8 @@ class CastFFNode: public ConstraintCastNode {
     
     class CastDDNode: public ConstraintCastNode {
     public:
    -  CastDDNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    -          : ConstraintCastNode(n, t, dependency, types) {
    +  CastDDNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    +          : ConstraintCastNode(ctrl, n, t, dependency, types) {
         init_class_id(Class_CastDD);
       }
       virtual int Opcode() const;
    @@ -169,8 +163,8 @@ class CastDDNode: public ConstraintCastNode {
     
     class CastVVNode: public ConstraintCastNode {
     public:
    -  CastVVNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    -          : ConstraintCastNode(n, t, dependency, types) {
    +  CastVVNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    +          : ConstraintCastNode(ctrl, n, t, dependency, types) {
         init_class_id(Class_CastVV);
       }
       virtual int Opcode() const;
    @@ -182,8 +176,8 @@ class CastVVNode: public ConstraintCastNode {
     // cast pointer to pointer (different type)
     class CastPPNode: public ConstraintCastNode {
       public:
    -  CastPPNode (Node *n, const Type *t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    -    : ConstraintCastNode(n, t, dependency, types) {
    +  CastPPNode (Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    +    : ConstraintCastNode(ctrl, n, t, dependency, types) {
       }
       virtual int Opcode() const;
       virtual uint ideal_reg() const { return Op_RegP; }
    @@ -193,10 +187,9 @@ class CastPPNode: public ConstraintCastNode {
     // for _checkcast, cast pointer to pointer (different type), without JOIN,
     class CheckCastPPNode: public ConstraintCastNode {
       public:
    -  CheckCastPPNode(Node *c, Node *n, const Type *t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    -    : ConstraintCastNode(n, t, dependency, types) {
    +  CheckCastPPNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr)
    +    : ConstraintCastNode(ctrl, n, t, dependency, types) {
         init_class_id(Class_CheckCastPP);
    -    init_req(0, c);
       }
     
       virtual Node* Identity(PhaseGVN* phase);
    diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
    index 621dafc24fc..4faec21328a 100644
    --- a/src/hotspot/share/opto/cfgnode.cpp
    +++ b/src/hotspot/share/opto/cfgnode.cpp
    @@ -2206,8 +2206,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
           if (phi_type->isa_ptr()) {
             const Type* uin_type = phase->type(uin);
             if (!phi_type->isa_oopptr() && !uin_type->isa_oopptr()) {
    -          cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, phi_type, ConstraintCastNode::StrongDependency,
    -                                               extra_types);
    +          cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types);
             } else {
               // Use a CastPP for a cast to not null and a CheckCastPP for
               // a cast to a new klass (and both if both null-ness and
    @@ -2217,8 +2216,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
               // null, uin's type must be casted to not null
               if (phi_type->join(TypePtr::NOTNULL) == phi_type->remove_speculative() &&
                   uin_type->join(TypePtr::NOTNULL) != uin_type->remove_speculative()) {
    -            cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, TypePtr::NOTNULL,
    -                                                 ConstraintCastNode::StrongDependency, extra_types);
    +            cast = new CastPPNode(r, uin, TypePtr::NOTNULL, ConstraintCastNode::StrongDependency, extra_types);
               }
     
               // If the type of phi and uin, both casted to not null,
    @@ -2230,12 +2228,10 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
                   cast = phase->transform(cast);
                   n = cast;
                 }
    -            cast = ConstraintCastNode::make_cast(Op_CheckCastPP, r, n, phi_type, ConstraintCastNode::StrongDependency,
    -                                                 extra_types);
    +            cast = new CheckCastPPNode(r, n, phi_type, ConstraintCastNode::StrongDependency, extra_types);
               }
               if (cast == nullptr) {
    -            cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, phi_type, ConstraintCastNode::StrongDependency,
    -                                                 extra_types);
    +            cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types);
               }
             }
           } else {
    diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp
    index 41f876cbbb1..02ea471a456 100644
    --- a/src/hotspot/share/opto/chaitin.cpp
    +++ b/src/hotspot/share/opto/chaitin.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1789,10 +1789,20 @@ void PhaseChaitin::fixup_spills() {
     // Helper to stretch above; recursively discover the base Node for a
     // given derived Node.  Easy for AddP-related machine nodes, but needs
     // to be recursive for derived Phis.
    -Node *PhaseChaitin::find_base_for_derived( Node **derived_base_map, Node *derived, uint &maxlrg ) {
    +Node* PhaseChaitin::find_base_for_derived(Node** derived_base_map, Node* derived, uint& maxlrg) {
       // See if already computed; if so return it
    -  if( derived_base_map[derived->_idx] )
    +  if (derived_base_map[derived->_idx]) {
         return derived_base_map[derived->_idx];
    +  }
    +
    +#ifdef ASSERT
    +  if (derived->is_Mach() && derived->as_Mach()->ideal_Opcode() == Op_VerifyVectorAlignment) {
    +    // Bypass the verification node
    +    Node* base = find_base_for_derived(derived_base_map, derived->in(1), maxlrg);
    +    derived_base_map[derived->_idx] = base;
    +    return base;
    +  }
    +#endif
     
       // See if this happens to be a base.
       // NOTE: we use TypePtr instead of TypeOopPtr because we can have
    diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp
    index dd917571b06..f01a8496125 100644
    --- a/src/hotspot/share/opto/chaitin.hpp
    +++ b/src/hotspot/share/opto/chaitin.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -163,8 +163,8 @@ class LRG : public ResourceObj {
       bool is_scalable() {
     #ifdef ASSERT
         if (_is_scalable) {
    -      assert(_is_vector && (_num_regs == RegMask::SlotsPerVecA) ||
    -             _is_predicate && (_num_regs == RegMask::SlotsPerRegVectMask), "unexpected scalable reg");
    +      assert((_is_vector && (_num_regs == RegMask::SlotsPerVecA)) ||
    +             (_is_predicate && (_num_regs == RegMask::SlotsPerRegVectMask)), "unexpected scalable reg");
         }
     #endif
         return Matcher::implements_scalable_vector && _is_scalable;
    diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp
    index 90d08a082d6..a7ae6d037c4 100644
    --- a/src/hotspot/share/opto/classes.hpp
    +++ b/src/hotspot/share/opto/classes.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -451,6 +451,7 @@ macro(StoreVectorScatter)
     macro(StoreVectorScatterMasked)
     macro(LoadVectorMasked)
     macro(StoreVectorMasked)
    +macro(VerifyVectorAlignment)
     macro(VectorCmpMasked)
     macro(VectorMaskGen)
     macro(VectorMaskOp)
    diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp
    index edf7c0e56ef..e510e0907be 100644
    --- a/src/hotspot/share/opto/compile.cpp
    +++ b/src/hotspot/share/opto/compile.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -29,9 +29,11 @@
     #include "classfile/javaClasses.hpp"
     #include "code/exceptionHandlerTable.hpp"
     #include "code/nmethod.hpp"
    +#include "compiler/compilationFailureInfo.hpp"
     #include "compiler/compilationMemoryStatistic.hpp"
     #include "compiler/compileBroker.hpp"
     #include "compiler/compileLog.hpp"
    +#include "compiler/compiler_globals.hpp"
     #include "compiler/disassembler.hpp"
     #include "compiler/oopMap.hpp"
     #include "gc/shared/barrierSet.hpp"
    @@ -651,6 +653,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
                       _directive(directive),
                       _log(ci_env->log()),
                       _failure_reason(nullptr),
    +                  _first_failure_details(nullptr),
                       _intrinsics        (comp_arena(), 0, 0, nullptr),
                       _macro_nodes       (comp_arena(), 8, 0, nullptr),
                       _parse_predicates  (comp_arena(), 8, 0, nullptr),
    @@ -755,7 +758,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
         TracePhase tp("parse", &timers[_t_parser]);
     
         // Put top into the hash table ASAP.
    -    initial_gvn()->transform_no_reclaim(top());
    +    initial_gvn()->transform(top());
     
         // Set up tf(), start(), and find a CallGenerator.
         CallGenerator* cg = nullptr;
    @@ -950,6 +953,7 @@ Compile::Compile( ciEnv* ci_env,
         _directive(directive),
         _log(ci_env->log()),
         _failure_reason(nullptr),
    +    _first_failure_details(nullptr),
         _congraph(nullptr),
         NOT_PRODUCT(_igv_printer(nullptr) COMMA)
         _unique(0),
    @@ -1002,7 +1006,7 @@ Compile::Compile( ciEnv* ci_env,
       {
         PhaseGVN gvn;
         set_initial_gvn(&gvn);    // not significant, but GraphKit guys use it pervasively
    -    gvn.transform_no_reclaim(top());
    +    gvn.transform(top());
     
         GraphKit kit;
         kit.gen_stub(stub_function, stub_name, is_fancy_jump, pass_tls, return_pc);
    @@ -1013,6 +1017,11 @@ Compile::Compile( ciEnv* ci_env,
       Code_Gen();
     }
     
    +Compile::~Compile() {
    +  delete _print_inlining_stream;
    +  delete _first_failure_details;
    +};
    +
     //------------------------------Init-------------------------------------------
     // Prepare for a single compilation
     void Compile::Init(bool aliasing) {
    @@ -1065,6 +1074,10 @@ void Compile::Init(bool aliasing) {
       Copy::zero_to_bytes(_trap_hist, sizeof(_trap_hist));
       set_decompile_count(0);
     
    +#ifndef PRODUCT
    +  Copy::zero_to_bytes(_igv_phase_iter, sizeof(_igv_phase_iter));
    +#endif
    +
       set_do_freq_based_layout(_directive->BlockLayoutByFrequencyOption);
       _loop_opts_cnt = LoopOptsCount;
       _has_flat_accesses = false;
    @@ -1080,7 +1093,7 @@ void Compile::Init(bool aliasing) {
       set_has_monitors(false);
     
       if (AllowVectorizeOnDemand) {
    -    if (has_method() && (_directive->VectorizeOption || _directive->VectorizeDebugOption)) {
    +    if (has_method() && _directive->VectorizeOption) {
           set_do_vector_loop(true);
           NOT_PRODUCT(if (do_vector_loop() && Verbose) {tty->print("Compile::Init: do vectorized loops (SIMD like) for method %s\n",  method()->name()->as_quoted_ascii());})
         } else if (has_method() && method()->name() != 0 &&
    @@ -2888,6 +2901,7 @@ void Compile::Optimize() {
       if (failing())  return;
     
       // Conditional Constant Propagation;
    +  print_method(PHASE_BEFORE_CCP1, 2);
       PhaseCCP ccp( &igvn );
       assert( true, "Break here to ccp.dump_nodes_and_types(_root,999,1)");
       {
    @@ -3467,6 +3481,8 @@ void Compile::Code_Gen() {
         if (failing()) {
           return;
         }
    +
    +    print_method(PHASE_REGISTER_ALLOCATION, 2);
       }
     
       // Prior to register allocation we kept empty basic blocks in case the
    @@ -3484,6 +3500,7 @@ void Compile::Code_Gen() {
         cfg.fixup_flow();
         cfg.remove_unreachable_blocks();
         cfg.verify_dominator_tree();
    +    print_method(PHASE_BLOCK_ORDERING, 3);
       }
     
       // Apply peephole optimizations
    @@ -3491,12 +3508,14 @@ void Compile::Code_Gen() {
         TracePhase tp("peephole", &timers[_t_peephole]);
         PhasePeephole peep( _regalloc, cfg);
         peep.do_transform();
    +    print_method(PHASE_PEEPHOLE, 3);
       }
     
       // Do late expand if CPU requires this.
       if (Matcher::require_postalloc_expand) {
         TracePhase tp("postalloc_expand", &timers[_t_postalloc_expand]);
         cfg.postalloc_expand(_regalloc);
    +    print_method(PHASE_POSTALLOC_EXPAND, 3);
       }
     
       // Convert Nodes to instruction bits in a buffer
    @@ -3626,8 +3645,8 @@ void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Uni
         int alias_idx = get_alias_index(n->as_Mem()->adr_type());
         assert( n->in(0) != nullptr || alias_idx != Compile::AliasIdxRaw ||
                 // oop will be recorded in oop map if load crosses safepoint
    -            n->is_Load() && (n->as_Load()->bottom_type()->isa_oopptr() ||
    -                             LoadNode::is_immutable_value(n->in(MemNode::Address))),
    +            (n->is_Load() && (n->as_Load()->bottom_type()->isa_oopptr() ||
    +                              LoadNode::is_immutable_value(n->in(MemNode::Address)))),
                 "raw memory operations should have control edge");
       }
       if (n->is_MemBar()) {
    @@ -4199,6 +4218,31 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
     
       case Op_LoadVector:
       case Op_StoreVector:
    +#ifdef ASSERT
    +    // Add VerifyVectorAlignment node between adr and load / store.
    +    if (VerifyAlignVector && Matcher::has_match_rule(Op_VerifyVectorAlignment)) {
    +      bool must_verify_alignment = n->is_LoadVector() ? n->as_LoadVector()->must_verify_alignment() :
    +                                                        n->as_StoreVector()->must_verify_alignment();
    +      if (must_verify_alignment) {
    +        jlong vector_width = n->is_LoadVector() ? n->as_LoadVector()->memory_size() :
    +                                                  n->as_StoreVector()->memory_size();
    +        // The memory access should be aligned to the vector width in bytes.
    +        // However, the underlying array is possibly less well aligned, but at least
    +        // to ObjectAlignmentInBytes. Hence, even if multiple arrays are accessed in
    +        // a loop we can expect at least the following alignment:
    +        jlong guaranteed_alignment = MIN2(vector_width, (jlong)ObjectAlignmentInBytes);
    +        assert(2 <= guaranteed_alignment && guaranteed_alignment <= 64, "alignment must be in range");
    +        assert(is_power_of_2(guaranteed_alignment), "alignment must be power of 2");
    +        // Create mask from alignment. e.g. 0b1000 -> 0b0111
    +        jlong mask = guaranteed_alignment - 1;
    +        Node* mask_con = ConLNode::make(mask);
    +        VerifyVectorAlignmentNode* va = new VerifyVectorAlignmentNode(n->in(MemNode::Address), mask_con);
    +        n->set_req(MemNode::Address, va);
    +      }
    +    }
    +#endif
    +    break;
    +
       case Op_LoadVectorGather:
       case Op_StoreVectorScatter:
       case Op_LoadVectorGatherMasked:
    @@ -4867,6 +4911,9 @@ void Compile::record_failure(const char* reason) {
       if (_failure_reason == nullptr) {
         // Record the first failure reason.
         _failure_reason = reason;
    +    if (CaptureBailoutInformation) {
    +      _first_failure_details = new CompilationFailureInfo(reason);
    +    }
       }
     
       if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) {
    @@ -4989,12 +5036,11 @@ Node* Compile::conv_I2X_index(PhaseGVN* phase, Node* idx, const TypeInt* sizetyp
     Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl, bool carry_dependency) {
       if (ctrl != nullptr) {
         // Express control dependency by a CastII node with a narrow type.
    -    value = new CastIINode(value, itype, carry_dependency ? ConstraintCastNode::StrongDependency : ConstraintCastNode::RegularDependency, true /* range check dependency */);
         // Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
         // node from floating above the range check during loop optimizations. Otherwise, the
         // ConvI2L node may be eliminated independently of the range check, causing the data path
         // to become TOP while the control path is still there (although it's unreachable).
    -    value->set_req(0, ctrl);
    +    value = new CastIINode(ctrl, value, itype, carry_dependency ? ConstraintCastNode::StrongDependency : ConstraintCastNode::RegularDependency, true /* range check dependency */);
         value = phase->transform(value);
       }
       const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen);
    @@ -5651,6 +5697,10 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) {
       ResourceMark rm;
       stringStream ss;
       ss.print_raw(CompilerPhaseTypeHelper::to_description(cpt));
    +  int iter = ++_igv_phase_iter[cpt];
    +  if (iter > 1) {
    +    ss.print(" %d", iter);
    +  }
       if (n != nullptr) {
         ss.print(": %d %s ", n->_idx, NodeClassNames[n->Opcode()]);
       }
    diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp
    index 38e9769e58f..d5afa3b4f2d 100644
    --- a/src/hotspot/share/opto/compile.hpp
    +++ b/src/hotspot/share/opto/compile.hpp
    @@ -54,6 +54,7 @@ class CallGenerator;
     class CallNode;
     class CallStaticJavaNode;
     class CloneMap;
    +class CompilationFailureInfo;
     class ConnectionGraph;
     class IdealGraphPrinter;
     class InlineTree;
    @@ -346,6 +347,7 @@ class Compile : public Phase {
       bool                  _print_intrinsics;      // True if we should print intrinsics for this compilation
     #ifndef PRODUCT
       uint                  _igv_idx;               // Counter for IGV node identifiers
    +  uint                  _igv_phase_iter[PHASE_NUM_TYPES]; // Counters for IGV phase iterations
       bool                  _trace_opto_output;
       bool                  _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing
     #endif
    @@ -368,6 +370,7 @@ class Compile : public Phase {
       DirectiveSet*         _directive;             // Compiler directive
       CompileLog*           _log;                   // from CompilerThread
       const char*           _failure_reason;        // for record_failure/failing pattern
    +  CompilationFailureInfo* _first_failure_details; // Details for the first failure happening during compilation
       GrowableArray _intrinsics;    // List of intrinsics.
       GrowableArray  _macro_nodes;           // List of nodes which need to be expanded before matching.
       GrowableArray _parse_predicates; // List of Parse Predicates.
    @@ -538,6 +541,7 @@ class Compile : public Phase {
     
     #ifndef PRODUCT
       IdealGraphPrinter* igv_printer() { return _igv_printer; }
    +  void reset_igv_phase_iter(CompilerPhaseType cpt) { _igv_phase_iter[cpt] = 0; }
     #endif
     
       void log_late_inline(CallGenerator* cg);
    @@ -833,6 +837,7 @@ class Compile : public Phase {
       CompileLog* log() const            { return _log; }
       bool        failing() const        { return _env->failing() || _failure_reason != nullptr; }
       const char* failure_reason() const { return (_env->failing()) ? _env->failure_reason() : _failure_reason; }
    +  const CompilationFailureInfo* first_failure_details() const { return _first_failure_details; }
     
       bool failure_reason_is(const char* r) const {
         return (r == _failure_reason) || (r != nullptr && _failure_reason != nullptr && strcmp(r, _failure_reason) == 0);
    @@ -1149,9 +1154,7 @@ class Compile : public Phase {
               int is_fancy_jump, bool pass_tls,
               bool return_pc, DirectiveSet* directive);
     
    -  ~Compile() {
    -    delete _print_inlining_stream;
    -  };
    +  ~Compile();
     
       // Are we compiling a method?
       bool has_method() { return method() != nullptr; }
    diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
    index 792fdef69b9..3d59f4ce66a 100644
    --- a/src/hotspot/share/opto/escape.cpp
    +++ b/src/hotspot/share/opto/escape.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -1148,7 +1148,7 @@ void ConnectionGraph::add_final_edges(Node *n) {
         return;
       }
       assert(n->is_Store() || n->is_LoadStore() ||
    -         (n_ptn != nullptr) && (n_ptn->ideal_node() != nullptr),
    +         ((n_ptn != nullptr) && (n_ptn->ideal_node() != nullptr)),
              "node should be registered already");
       int opcode = n->Opcode();
       bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_final_edges(this, _igvn, n, opcode);
    @@ -3937,7 +3937,7 @@ void ConnectionGraph::split_unique_types(GrowableArray  &alloc_worklist,
               record_for_optimizer(n);
             } else {
               assert(tn_type == TypePtr::NULL_PTR ||
    -                 tn_t != nullptr && !tinst->maybe_java_subtype_of(tn_t),
    +                 (tn_t != nullptr && !tinst->maybe_java_subtype_of(tn_t)),
                      "unexpected type");
               continue; // Skip dead path with different type
             }
    diff --git a/src/hotspot/share/opto/generateOptoStub.cpp b/src/hotspot/share/opto/generateOptoStub.cpp
    index 58e709fd705..4a0f43824fa 100644
    --- a/src/hotspot/share/opto/generateOptoStub.cpp
    +++ b/src/hotspot/share/opto/generateOptoStub.cpp
    @@ -193,7 +193,7 @@ void GraphKit::gen_stub(address C_function,
         call->init_req(cnt++, returnadr());
       }
     
    -  _gvn.transform_no_reclaim(call);
    +  _gvn.transform(call);
     
       //-----------------------------
       // Now set up the return results
    diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
    index 572ae746cf6..59db0170ca7 100644
    --- a/src/hotspot/share/opto/graphKit.cpp
    +++ b/src/hotspot/share/opto/graphKit.cpp
    @@ -1500,8 +1500,7 @@ Node* GraphKit::cast_not_null(Node* obj, bool do_replace_in_map) {
       // Object is already not-null?
       if( t == t_not_null ) return obj;
     
    -  Node *cast = new CastPPNode(obj,t_not_null);
    -  cast->init_req(0, control());
    +  Node* cast = new CastPPNode(control(), obj,t_not_null);
       cast = _gvn.transform( cast );
     
       // Scan for instances of 'obj' in the current JVM mapping.
    @@ -1625,6 +1624,11 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
       if (((bt == T_OBJECT) && C->do_escape_analysis()) || C->eliminate_boxing()) {
         // Improve graph before escape analysis and boxing elimination.
         record_for_igvn(ld);
    +    if (ld->is_DecodeN()) {
    +      // Also record the actual load (LoadN) in case ld is DecodeN
    +      assert(ld->in(1)->Opcode() == Op_LoadN, "Assumption invalid: input to DecodeN is not LoadN");
    +      record_for_igvn(ld->in(1));
    +    }
       }
       return ld;
     }
    diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp
    index 15255822c66..08b67f782a0 100644
    --- a/src/hotspot/share/opto/lcm.cpp
    +++ b/src/hotspot/share/opto/lcm.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -150,8 +150,9 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo
       bool is_decoden = ((intptr_t)val) & 1;
       val = (Node*)(((intptr_t)val) & ~1);
     
    -  assert(!is_decoden || (val->in(0) == nullptr) && val->is_Mach() &&
    -         (val->as_Mach()->ideal_Opcode() == Op_DecodeN), "sanity");
    +  assert(!is_decoden ||
    +         ((val->in(0) == nullptr) && val->is_Mach() &&
    +          (val->as_Mach()->ideal_Opcode() == Op_DecodeN)), "sanity");
     
       // Search the successor block for a load or store who's base value is also
       // the tested value.  There may be several.
    diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
    index 6336082af6f..fc83c30ffb1 100644
    --- a/src/hotspot/share/opto/library_call.cpp
    +++ b/src/hotspot/share/opto/library_call.cpp
    @@ -497,7 +497,8 @@ bool LibraryCallKit::try_to_inline(int predicate) {
                                                                                              "notifyJvmtiMount", false, false);
       case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()),
                                                                                              "notifyJvmtiUnmount", false, false);
    -  case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide();
    +  case vmIntrinsics::_notifyJvmtiVThreadHideFrames:     return inline_native_notify_jvmti_hide();
    +  case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync();
     #endif
     
     #ifdef JFR_HAVE_INTRINSICS
    @@ -879,8 +880,7 @@ inline Node* LibraryCallKit::generate_negative_guard(Node* index, RegionNode* re
       Node* is_neg = generate_guard(bol_lt, region, PROB_MIN);
       if (is_neg != nullptr && pos_index != nullptr) {
         // Emulate effect of Parse::adjust_map_after_if.
    -    Node* ccast = new CastIINode(index, TypeInt::POS);
    -    ccast->set_req(0, control());
    +    Node* ccast = new CastIINode(control(), index, TypeInt::POS);
         (*pos_index) = _gvn.transform(ccast);
       }
       return is_neg;
    @@ -1147,7 +1147,9 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) {
     
       // length is now known positive, add a cast node to make this explicit
       jlong upper_bound = _gvn.type(length)->is_integer(bt)->hi_as_long();
    -  Node* casted_length = ConstraintCastNode::make(control(), length, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), ConstraintCastNode::RegularDependency, bt);
    +  Node* casted_length = ConstraintCastNode::make_cast_for_basic_type(
    +      control(), length, TypeInteger::make(0, upper_bound, Type::WidenMax, bt),
    +      ConstraintCastNode::RegularDependency, bt);
       casted_length = _gvn.transform(casted_length);
       replace_in_map(length, casted_length);
       length = casted_length;
    @@ -1175,7 +1177,9 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) {
       }
     
       // index is now known to be >= 0 and < length, cast it
    -  Node* result = ConstraintCastNode::make(control(), index, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), ConstraintCastNode::RegularDependency, bt);
    +  Node* result = ConstraintCastNode::make_cast_for_basic_type(
    +      control(), index, TypeInteger::make(0, upper_bound, Type::WidenMax, bt),
    +      ConstraintCastNode::RegularDependency, bt);
       result = _gvn.transform(result);
       set_result(result);
       replace_in_map(index, result);
    @@ -3153,6 +3157,29 @@ bool LibraryCallKit::inline_native_notify_jvmti_hide() {
       return true;
     }
     
    +// Always update the is_disable_suspend bit.
    +bool LibraryCallKit::inline_native_notify_jvmti_sync() {
    +  if (!DoJVMTIVirtualThreadTransitions) {
    +    return true;
    +  }
    +  IdealKit ideal(this);
    +
    +  {
    +    // unconditionally update the is_disable_suspend bit in current JavaThread
    +    Node* thread = ideal.thread();
    +    Node* arg = _gvn.transform(argument(1)); // argument for notification
    +    Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_disable_suspend_offset()));
    +    const TypePtr *addr_type = _gvn.type(addr)->isa_ptr();
    +
    +    sync_kit(ideal);
    +    access_store_at(nullptr, addr, addr_type, arg, _gvn.type(arg), T_BOOLEAN, IN_NATIVE | MO_UNORDERED);
    +    ideal.sync_kit(this);
    +  }
    +  final_sync(ideal);
    +
    +  return true;
    +}
    +
     #endif // INCLUDE_JVMTI
     
     #ifdef JFR_HAVE_INTRINSICS
    @@ -4548,8 +4575,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
           // Improve the klass node's type from the new optimistic assumption:
           ciKlass* ak = ciArrayKlass::make(env()->Object_klass());
           const Type* akls = TypeKlassPtr::make(TypePtr::NotNull, ak, Type::Offset(0));
    -      Node* cast = new CastPPNode(klass_node, akls);
    -      cast->init_req(0, control());
    +      Node* cast = new CastPPNode(control(), klass_node, akls);
           klass_node = _gvn.transform(cast);
         }
     
    @@ -5735,6 +5761,10 @@ bool LibraryCallKit::inline_array_partition() {
         const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr();
         ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type();
         BasicType bt = elem_type->basic_type();
    +    // Disable the intrinsic if the CPU does not support SIMD sort
    +    if (!Matcher::supports_simd_sort(bt)) {
    +      return false;
    +    }
         address stubAddr = nullptr;
         stubAddr = StubRoutines::select_array_partition_function();
         // stub not loaded
    @@ -5788,6 +5818,10 @@ bool LibraryCallKit::inline_array_sort() {
       const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr();
       ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type();
       BasicType bt = elem_type->basic_type();
    +  // Disable the intrinsic if the CPU does not support SIMD sort
    +  if (!Matcher::supports_simd_sort(bt)) {
    +    return false;
    +  }
       address stubAddr = nullptr;
       stubAddr = StubRoutines::select_arraysort_function();
       //stub not loaded
    @@ -6280,8 +6314,7 @@ bool LibraryCallKit::inline_multiplyToLen() {
          } __ else_(); {
            // Update graphKit memory and control from IdealKit.
            sync_kit(ideal);
    -       Node *cast = new CastPPNode(z, TypePtr::NOTNULL);
    -       cast->init_req(0, control());
    +       Node* cast = new CastPPNode(control(), z, TypePtr::NOTNULL);
            _gvn.set_type(cast, cast->bottom_type());
            C->record_for_igvn(cast);
     
    diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp
    index 1189df3f6de..c86dfaf0067 100644
    --- a/src/hotspot/share/opto/library_call.hpp
    +++ b/src/hotspot/share/opto/library_call.hpp
    @@ -269,6 +269,7 @@ class LibraryCallKit : public GraphKit {
     #if INCLUDE_JVMTI
       bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end);
       bool inline_native_notify_jvmti_hide();
    +  bool inline_native_notify_jvmti_sync();
     #endif
     
     #ifdef JFR_HAVE_INTRINSICS
    diff --git a/src/hotspot/share/opto/locknode.cpp b/src/hotspot/share/opto/locknode.cpp
    index b4519120fc0..62f8626015a 100644
    --- a/src/hotspot/share/opto/locknode.cpp
    +++ b/src/hotspot/share/opto/locknode.cpp
    @@ -199,8 +199,6 @@ void Parse::do_monitor_enter() {
         return;
       }
     
    -  C->set_has_monitors(true);
    -
       // Null check; get casted pointer.
       obj = null_check(obj);
       // Check for locking null object
    @@ -218,10 +216,6 @@ void Parse::do_monitor_enter() {
     void Parse::do_monitor_exit() {
       kill_dead_locals();
     
    -  // need to set it for monitor exit as well.
    -  // OSR compiled methods can start with lock taken
    -  C->set_has_monitors(true);
    -
       pop();                        // Pop oop to unlock
       // Because monitors are guaranteed paired (else we bail out), we know
       // the matching Lock for this Unlock.  Hence we know there is no need
    diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp
    index d569bfcfab5..6a8efb0872a 100644
    --- a/src/hotspot/share/opto/loopPredicate.cpp
    +++ b/src/hotspot/share/opto/loopPredicate.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -797,7 +797,8 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal
       overflow = false;
       Node* max_idx_expr = nullptr;
       const TypeInt* idx_type = TypeInt::INT;
    -  if ((stride > 0) == (scale > 0) == upper) {
    +  // same signs and upper, or different signs and not upper.
    +  if (((stride > 0) == (scale > 0)) == upper) {
         guarantee(limit != nullptr, "sanity");
         if (TraceLoopPredicate) {
           if (limit->is_Con()) {
    @@ -1180,6 +1181,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
       }
       BoolNode* bol = test->as_Bool();
       if (invar.is_invariant(bol)) {
    +    C->print_method(PHASE_BEFORE_LOOP_PREDICATION_IC, 4, iff);
         // Invariant test
         new_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr,
                                                          reason,
    @@ -1197,6 +1199,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
         IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If();
         _igvn.hash_delete(new_predicate_iff);
         new_predicate_iff->set_req(1, new_predicate_bol);
    +
    +    C->print_method(PHASE_AFTER_LOOP_PREDICATION_IC, 4, new_predicate_proj->in(0));
    +
     #ifndef PRODUCT
         if (TraceLoopPredicate) {
           tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx);
    @@ -1207,6 +1212,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
         }
     #endif
       } else if (cl != nullptr && loop->is_range_check_if(if_success_proj, this, invar DEBUG_ONLY(COMMA parse_predicate_proj))) {
    +    C->print_method(PHASE_BEFORE_LOOP_PREDICATION_RC, 4, iff);
         // Range check for counted loops
         assert(if_success_proj->is_IfTrue(), "trap must be on false projection for a range check");
         const Node*    cmp    = bol->in(1)->as_Cmp();
    @@ -1270,6 +1276,8 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
         new_predicate_proj = add_template_assertion_predicate(iff, loop, if_success_proj, parse_predicate_proj, upper_bound_proj, scale,
                                                               offset, init, limit, stride, rng, overflow, reason);
     
    +    C->print_method(PHASE_AFTER_LOOP_PREDICATION_RC, 4, new_predicate_proj->in(0));
    +
     #ifndef PRODUCT
         if (TraceLoopOpts && !TraceLoopPredicate) {
           tty->print("Predicate RC ");
    diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp
    index 22386b144c2..3d3e7bdaa7c 100644
    --- a/src/hotspot/share/opto/loopTransform.cpp
    +++ b/src/hotspot/share/opto/loopTransform.cpp
    @@ -703,6 +703,9 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) {
       }
     #endif
       LoopNode* head = loop->_head->as_Loop();
    +
    +  C->print_method(PHASE_BEFORE_LOOP_PEELING, 4, head);
    +
       bool counted_loop = head->is_CountedLoop();
       if (counted_loop) {
         CountedLoopNode *cl = head->as_CountedLoop();
    @@ -795,6 +798,8 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) {
       peeled_dom_test_elim(loop,old_new);
     
       loop->record_for_igvn();
    +
    +  C->print_method(PHASE_AFTER_LOOP_PEELING, 4, new_head);
     }
     
     //------------------------------policy_maximally_unroll------------------------
    @@ -1279,8 +1284,7 @@ Node *PhaseIdealLoop::clone_up_backedge_goo(Node *back_ctrl, Node *preheader_ctr
     }
     
     Node* PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop) {
    -  Node* castii = new CastIINode(incr, TypeInt::INT, ConstraintCastNode::UnconditionalDependency);
    -  castii->set_req(0, ctrl);
    +  Node* castii = new CastIINode(ctrl, incr, TypeInt::INT, ConstraintCastNode::UnconditionalDependency);
       register_new_node(castii, ctrl);
       for (DUIterator_Fast imax, i = incr->fast_outs(imax); i < imax; i++) {
         Node* n = incr->fast_out(i);
    @@ -1629,6 +1633,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n
       CountedLoopEndNode *main_end = main_head->loopexit();
       assert(main_end->outcnt() == 2, "1 true, 1 false path only");
     
    +  C->print_method(PHASE_BEFORE_PRE_MAIN_POST, 4, main_head);
    +
       Node *pre_header= main_head->in(LoopNode::EntryControl);
       Node *init      = main_head->init_trip();
       Node *incr      = main_end ->incr();
    @@ -1825,6 +1831,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n
       // finds some, but we _know_ they are all useless.
       peeled_dom_test_elim(loop,old_new);
       loop->record_for_igvn();
    +
    +  C->print_method(PHASE_AFTER_PRE_MAIN_POST, 4, main_head);
     }
     
     //------------------------------insert_vector_post_loop------------------------
    @@ -2127,6 +2135,9 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj
       assert(LoopUnrollLimit, "");
       CountedLoopNode *loop_head = loop->_head->as_CountedLoop();
       CountedLoopEndNode *loop_end = loop_head->loopexit();
    +
    +  C->print_method(PHASE_BEFORE_LOOP_UNROLLING, 4, loop_head);
    +
     #ifndef PRODUCT
       if (PrintOpto && VerifyLoopOptimizations) {
         tty->print("Unrolling ");
    @@ -2374,6 +2385,8 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj
         }
       }
     #endif
    +
    +  C->print_method(PHASE_AFTER_LOOP_UNROLLING, 4, clone_head);
     }
     
     //------------------------------do_maximally_unroll----------------------------
    @@ -3003,6 +3016,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
           // stride_con and scale_con can be negative which will flip about the
           // sense of the test.
     
    +      C->print_method(PHASE_BEFORE_RANGE_CHECK_ELIMINATION, 4, iff);
    +
           // Perform the limit computations in jlong to avoid overflow
           jlong lscale_con = scale_con;
           Node* int_offset = offset;
    @@ -3103,6 +3118,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
               --imax;
             }
           }
    +
    +      C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl);
    +
         } // End of is IF
       }
       if (loop_entry != cl->skip_strip_mined()->in(LoopNode::EntryControl)) {
    @@ -3142,9 +3160,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
       // The new loop limit is <= (for an upward loop) >= (for a downward loop) than the orig limit.
       // The expression that computes the new limit may be too complicated and the computed type of the new limit
       // may be too pessimistic. A CastII here guarantees it's not lost.
    -  main_limit = new CastIINode(main_limit, TypeInt::make(upward ? min_jint : orig_limit_t->_lo,
    +  main_limit = new CastIINode(pre_ctrl, main_limit, TypeInt::make(upward ? min_jint : orig_limit_t->_lo,
                                                             upward ? orig_limit_t->_hi : max_jint, Type::WidenMax));
    -  main_limit->init_req(0, pre_ctrl);
       register_new_node(main_limit, pre_ctrl);
       // Hack the now-private loop bounds
       _igvn.replace_input_of(main_cmp, 2, main_limit);
    @@ -3403,7 +3420,10 @@ bool IdealLoopTree::do_remove_empty_loop(PhaseIdealLoop *phase) {
       Node* exact_limit = phase->exact_limit(this);
     
       // We need to pin the exact limit to prevent it from floating above the zero trip guard.
    -  Node* cast_ii = ConstraintCastNode::make(cl->in(LoopNode::EntryControl), exact_limit, phase->_igvn.type(exact_limit), ConstraintCastNode::UnconditionalDependency, T_INT);
    +  Node* cast_ii = ConstraintCastNode::make_cast_for_basic_type(
    +      cl->in(LoopNode::EntryControl), exact_limit,
    +      phase->_igvn.type(exact_limit),
    +      ConstraintCastNode::UnconditionalDependency, T_INT);
       phase->register_new_node(cast_ii, cl->in(LoopNode::EntryControl));
     
       Node* final_iv = new SubINode(cast_ii, cl->stride());
    diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp
    index dd2b6001352..8b6f02de63c 100644
    --- a/src/hotspot/share/opto/loopUnswitch.cpp
    +++ b/src/hotspot/share/opto/loopUnswitch.cpp
    @@ -167,6 +167,8 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) {
       }
     #endif
     
    +  C->print_method(PHASE_BEFORE_LOOP_UNSWITCHING, 4, head);
    +
       // Need to revert back to normal loop
       if (head->is_CountedLoop() && !head->as_CountedLoop()->is_normal_loop()) {
         head->as_CountedLoop()->set_normal_loop();
    @@ -246,6 +248,8 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) {
       }
     #endif
     
    +  C->print_method(PHASE_AFTER_LOOP_UNSWITCHING, 4, head_clone);
    +
       C->set_major_progress();
     }
     
    diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
    index 0f3994dea34..02c8c2bf40d 100644
    --- a/src/hotspot/share/opto/loopopts.cpp
    +++ b/src/hotspot/share/opto/loopopts.cpp
    @@ -797,25 +797,18 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) {
       // Avoid duplicated float compare.
       if (phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return nullptr;
     
    -  float infrequent_prob = PROB_UNLIKELY_MAG(3);
    -  // Ignore cost and blocks frequency if CMOVE can be moved outside the loop.
    -  if (used_inside_loop) {
    -    if (cost >= ConditionalMoveLimit) return nullptr; // Too much goo
    -
    -    // BlockLayoutByFrequency optimization moves infrequent branch
    -    // from hot path. No point in CMOV'ing in such case (110 is used
    -    // instead of 100 to take into account not exactness of float value).
    -    if (BlockLayoutByFrequency) {
    -      infrequent_prob = MAX2(infrequent_prob, (float)BlockLayoutMinDiamondPercentage/110.0f);
    -    }
    +  // Ignore cost if CMOVE can be moved outside the loop.
    +  if (used_inside_loop && cost >= ConditionalMoveLimit) {
    +    return nullptr;
       }
       // Check for highly predictable branch.  No point in CMOV'ing if
       // we are going to predict accurately all the time.
    +  constexpr float infrequent_prob = PROB_UNLIKELY_MAG(2);
       if (C->use_cmove() && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) {
         //keep going
    -  } else if (iff->_prob < infrequent_prob ||
    -      iff->_prob > (1.0f - infrequent_prob))
    +  } else if (iff->_prob < infrequent_prob || iff->_prob > (1.0f - infrequent_prob)) {
         return nullptr;
    +  }
     
       // --------------
       // Now replace all Phis with CMOV's
    @@ -1614,7 +1607,12 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
         }
     
         // Now split the IF
    +    C->print_method(PHASE_BEFORE_SPLIT_IF, 4, iff);
    +    if ((PrintOpto && VerifyLoopOptimizations) || TraceLoopOpts) {
    +      tty->print_cr("Split-If");
    +    }
         do_split_if(iff);
    +    C->print_method(PHASE_AFTER_SPLIT_IF, 4, iff);
         return;
       }
     
    @@ -3806,6 +3804,9 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
         }
       }
     #endif
    +
    +  C->print_method(PHASE_BEFORE_PARTIAL_PEELING, 4, head);
    +
       VectorSet peel;
       VectorSet not_peel;
       Node_List peel_list;
    @@ -4100,6 +4101,9 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
         }
       }
     #endif
    +
    +  C->print_method(PHASE_AFTER_PARTIAL_PEELING, 4, new_head_clone);
    +
       return true;
     }
     
    diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp
    index ed805ba1108..86f5d8d76c6 100644
    --- a/src/hotspot/share/opto/machnode.cpp
    +++ b/src/hotspot/share/opto/machnode.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -357,6 +357,13 @@ const class TypePtr *MachNode::adr_type() const {
         return adr_type;      // get_base_and_disp has the answer
       }
     
    +#ifdef ASSERT
    +  if (base != nullptr && base->is_Mach() && base->as_Mach()->ideal_Opcode() == Op_VerifyVectorAlignment) {
    +    // For VerifyVectorAlignment we just pass the type through
    +    return base->bottom_type()->is_ptr();
    +  }
    +#endif
    +
       // Direct addressing modes have no base node, simply an indirect
       // offset, which is always to raw memory.
       // %%%%% Someday we'd like to allow constant oop offsets which
    diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp
    index fe37f6a131a..1c02c8f70dd 100644
    --- a/src/hotspot/share/opto/macro.cpp
    +++ b/src/hotspot/share/opto/macro.cpp
    @@ -323,7 +323,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset,
             // own slice so we need to extract the field being accessed from
             // the address computation
             adr_type = adr_type->add_field_offset_and_offset(offset)->add_offset(Type::OffsetBot)->is_aryptr();
    -        adr = _igvn.transform(new CastPPNode(adr, adr_type));
    +        adr = _igvn.transform(new CastPPNode(ctl, adr, adr_type));
           }
           MergeMemNode* mergemen = _igvn.transform(MergeMemNode::make(mem))->as_MergeMem();
           BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
    diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp
    index 4125548da47..109722f9938 100644
    --- a/src/hotspot/share/opto/memnode.cpp
    +++ b/src/hotspot/share/opto/memnode.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -5051,7 +5051,7 @@ static void verify_memory_slice(const MergeMemNode* m, int alias_idx, Node* n) {
     //-----------------------------memory_at---------------------------------------
     Node* MergeMemNode::memory_at(uint alias_idx) const {
       assert(alias_idx >= Compile::AliasIdxRaw ||
    -         alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing(),
    +         (alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing()),
              "must avoid base_memory and AliasIdxTop");
     
       // Otherwise, it is a narrow slice.
    diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp
    index d8412d0b45b..dc78c77b00b 100644
    --- a/src/hotspot/share/opto/memnode.hpp
    +++ b/src/hotspot/share/opto/memnode.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -791,7 +791,7 @@ class StoreCMNode : public StoreNode {
         StoreNode(c, mem, adr, at, val, oop_store, MemNode::release),
         _oop_alias_idx(oop_alias_idx) {
         assert(_oop_alias_idx >= Compile::AliasIdxRaw ||
    -           _oop_alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing(),
    +           (_oop_alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing()),
                "bad oop alias idx");
       }
       virtual int Opcode() const;
    diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp
    index 5b6712f916f..92da534ad74 100644
    --- a/src/hotspot/share/opto/mulnode.cpp
    +++ b/src/hotspot/share/opto/mulnode.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -622,6 +622,13 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) {
         return progress;
       }
     
    +  // Convert "(~a) & (~b)" into "~(a | b)"
    +  if (AddNode::is_not(phase, in(1), T_INT) && AddNode::is_not(phase, in(2), T_INT)) {
    +    Node* or_a_b = new OrINode(in(1)->in(1), in(2)->in(1));
    +    Node* tn = phase->transform(or_a_b);
    +    return AddNode::make_not(phase, tn, T_INT);
    +  }
    +
       // Special case constant AND mask
       const TypeInt *t2 = phase->type( in(2) )->isa_int();
       if( !t2 || !t2->is_con() ) return MulNode::Ideal(phase, can_reshape);
    @@ -770,6 +777,13 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
         return progress;
       }
     
    +  // Convert "(~a) & (~b)" into "~(a | b)"
    +  if (AddNode::is_not(phase, in(1), T_LONG) && AddNode::is_not(phase, in(2), T_LONG)) {
    +    Node* or_a_b = new OrLNode(in(1)->in(1), in(2)->in(1));
    +    Node* tn = phase->transform(or_a_b);
    +    return AddNode::make_not(phase, tn, T_LONG);
    +  }
    +
       // Special case constant AND mask
       const TypeLong *t2 = phase->type( in(2) )->isa_long();
       if( !t2 || !t2->is_con() ) return MulNode::Ideal(phase, can_reshape);
    diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp
    index 992f246fcc0..9ab1e855533 100644
    --- a/src/hotspot/share/opto/node.hpp
    +++ b/src/hotspot/share/opto/node.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -182,6 +182,7 @@ class StoreVectorMaskedNode;
     class LoadVectorGatherNode;
     class StoreVectorNode;
     class StoreVectorScatterNode;
    +class VerifyVectorAlignmentNode;
     class VectorMaskCmpNode;
     class VectorUnboxNode;
     class VectorSet;
    @@ -452,7 +453,7 @@ class Node {
       }
       // Light version of set_req() to init inputs after node creation.
       void init_req( uint i, Node *n ) {
    -    assert( i == 0 && this == n ||
    +    assert( (i == 0 && this == n) ||
                 is_not_dead(n), "can not use dead node");
         assert( i < _cnt, "oob");
         assert( !VerifyHashTableKeys || _hash_lock == 0,
    diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp
    index 07f49094da2..c788a8fa84f 100644
    --- a/src/hotspot/share/opto/parse.hpp
    +++ b/src/hotspot/share/opto/parse.hpp
    @@ -416,8 +416,11 @@ class Parse : public GraphKit {
       void set_block(Block* b)            { _block = b; }
     
       // Derived accessors:
    -  bool is_normal_parse() const  { return _entry_bci == InvocationEntryBci; }
    -  bool is_osr_parse() const     { return _entry_bci != InvocationEntryBci; }
    +  bool is_osr_parse() const {
    +    assert(_entry_bci != UnknownBci, "uninitialized _entry_bci");
    +    return _entry_bci != InvocationEntryBci;
    +  }
    +  bool is_normal_parse() const  { return !is_osr_parse(); }
       int osr_bci() const           { assert(is_osr_parse(),""); return _entry_bci; }
     
       void set_parse_bci(int bci);
    diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp
    index b2d33a12816..1a2784ec4f2 100644
    --- a/src/hotspot/share/opto/parse1.cpp
    +++ b/src/hotspot/share/opto/parse1.cpp
    @@ -405,19 +405,17 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
       _wrote_stable = false;
       _wrote_fields = false;
       _alloc_with_final = nullptr;
    -  _entry_bci = InvocationEntryBci;
    -  _tf = nullptr;
       _block = nullptr;
       _first_return = true;
       _replaced_nodes_for_exceptions = false;
       _new_idx = C->unique();
    -  debug_only(_block_count = -1);
    -  debug_only(_blocks = (Block*)-1);
    +  DEBUG_ONLY(_entry_bci = UnknownBci);
    +  DEBUG_ONLY(_block_count = -1);
    +  DEBUG_ONLY(_blocks = (Block*)-1);
     #ifndef PRODUCT
       if (PrintCompilation || PrintOpto) {
         // Make sure I have an inline tree, so I can print messages about it.
    -    JVMState* ilt_caller = is_osr_parse() ? caller->caller() : caller;
    -    InlineTree::find_subtree_from_root(C->ilt(), ilt_caller, parse_method);
    +    InlineTree::find_subtree_from_root(C->ilt(), caller, parse_method);
       }
       _max_switch_depth = 0;
       _est_switch_depth = 0;
    @@ -427,23 +425,11 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
         C->set_has_reserved_stack_access(true);
       }
     
    -  if (parse_method->is_synchronized()) {
    +  if (parse_method->is_synchronized() || parse_method->has_monitor_bytecodes()) {
         C->set_has_monitors(true);
       }
     
    -  _tf = TypeFunc::make(method());
       _iter.reset_to_method(method());
    -  _flow = method()->get_flow_analysis();
    -  if (_flow->failing()) {
    -    assert(false, "type flow failed during parsing");
    -    C->record_method_not_compilable(_flow->failure_reason());
    -  }
    -
    -#ifndef PRODUCT
    -  if (_flow->has_irreducible_entry()) {
    -    C->set_parsed_irreducible_loop(true);
    -  }
    -#endif
       C->set_has_loops(C->has_loops() || method()->has_loops());
     
       if (_expected_uses <= 0) {
    @@ -511,16 +497,27 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
     
       // Do some special top-level things.
       if (depth() == 1 && C->is_osr_compilation()) {
    +    _tf = C->tf();     // the OSR entry type is different
         _entry_bci = C->entry_bci();
         _flow = method()->get_osr_flow_analysis(osr_bci());
    -    if (_flow->failing()) {
    -      // TODO Adding a trap due to an unloaded return type in ciTypeFlow::StateVector::do_invoke
    -      // can lead to this. Re-enable once 8284443 is fixed.
    -      // assert(false, "type flow analysis failed for OSR compilation");
    -      C->record_method_not_compilable(_flow->failure_reason());
    +  } else {
    +    _tf = TypeFunc::make(method());
    +    _entry_bci = InvocationEntryBci;
    +    _flow = method()->get_flow_analysis();
    +  }
    +
    +  if (_flow->failing()) {
    +    // TODO Adding a trap due to an unloaded return type in ciTypeFlow::StateVector::do_invoke
    +    // can lead to this. Re-enable once 8284443 is fixed.
    +    //assert(false, "type flow analysis failed during parsing");
    +    C->record_method_not_compilable(_flow->failure_reason());
     #ifndef PRODUCT
           if (PrintOpto && (Verbose || WizardMode)) {
    -        tty->print_cr("OSR @%d type flow bailout: %s", _entry_bci, _flow->failure_reason());
    +        if (is_osr_parse()) {
    +          tty->print_cr("OSR @%d type flow bailout: %s", _entry_bci, _flow->failure_reason());
    +        } else {
    +          tty->print_cr("type flow bailout: %s", _flow->failure_reason());
    +        }
             if (Verbose) {
               method()->print();
               method()->print_codes();
    @@ -528,8 +525,6 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
             }
           }
     #endif
    -    }
    -    _tf = C->tf();     // the OSR entry type is different
       }
     
     #ifdef ASSERT
    @@ -541,6 +536,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
     #endif
     
     #ifndef PRODUCT
    +  if (_flow->has_irreducible_entry()) {
    +    C->set_parsed_irreducible_loop(true);
    +  }
    +
       methods_parsed++;
       // add method size here to guarantee that inlined methods are added too
       if (CITime)
    @@ -729,7 +728,7 @@ void Parse::do_all_blocks() {
             // that any path which was supposed to reach here has already
             // been parsed or must be dead.
             Node* c = control();
    -        Node* result = _gvn.transform_no_reclaim(control());
    +        Node* result = _gvn.transform(control());
             if (c != result && TraceOptoParse) {
               tty->print_cr("Block #%d replace %d with %d", block->rpo(), c->_idx, result->_idx);
             }
    @@ -952,7 +951,7 @@ void Compile::return_values(JVMState* jvms) {
       // bind it to root
       root()->add_req(ret);
       record_for_igvn(ret);
    -  initial_gvn()->transform_no_reclaim(ret);
    +  initial_gvn()->transform(ret);
     }
     
     //------------------------rethrow_exceptions-----------------------------------
    @@ -971,7 +970,7 @@ void Compile::rethrow_exceptions(JVMState* jvms) {
       // bind to root
       root()->add_req(exit);
       record_for_igvn(exit);
    -  initial_gvn()->transform_no_reclaim(exit);
    +  initial_gvn()->transform(exit);
     }
     
     //---------------------------do_exceptions-------------------------------------
    @@ -1589,13 +1588,13 @@ void Parse::do_one_block() {
         int ns = b->num_successors();
         int nt = b->all_successors();
     
    -    tty->print("Parsing block #%d at bci [%d,%d), successors: ",
    +    tty->print("Parsing block #%d at bci [%d,%d), successors:",
                       block()->rpo(), block()->start(), block()->limit());
         for (int i = 0; i < nt; i++) {
    -      tty->print((( i < ns) ? " %d" : " %d(e)"), b->successor_at(i)->rpo());
    +      tty->print((( i < ns) ? " %d" : " %d(exception block)"), b->successor_at(i)->rpo());
         }
         if (b->is_loop_head()) {
    -      tty->print("  lphd");
    +      tty->print("  loop head");
         }
         if (b->is_irreducible_loop_entry()) {
           tty->print("  irreducible");
    @@ -1881,7 +1880,7 @@ void Parse::merge_common(Parse::Block* target, int pnum) {
     
         if (pnum == 1) {            // Last merge for this Region?
           if (!block()->flow()->is_irreducible_loop_secondary_entry()) {
    -        Node* result = _gvn.transform_no_reclaim(r);
    +        Node* result = _gvn.transform(r);
             if (r != result && TraceOptoParse) {
               tty->print_cr("Block #%d replace %d with %d", block()->rpo(), r->_idx, result->_idx);
             }
    @@ -1957,7 +1956,7 @@ void Parse::merge_common(Parse::Block* target, int pnum) {
             // Do the merge
             vtm->merge_with(&_gvn, vtn, pnum, last_merge);
             if (last_merge) {
    -          map()->set_req(j, _gvn.transform_no_reclaim(vtm));
    +          map()->set_req(j, _gvn.transform(vtm));
               record_for_igvn(vtm);
             }
           } else if (phi != nullptr) {
    @@ -1972,7 +1971,7 @@ void Parse::merge_common(Parse::Block* target, int pnum) {
               // Phis of pointers cannot lose the basic pointer type.
               debug_only(const Type* bt1 = phi->bottom_type());
               assert(bt1 != Type::BOTTOM, "should not be building conflict phis");
    -          map()->set_req(j, _gvn.transform_no_reclaim(phi));
    +          map()->set_req(j, _gvn.transform(phi));
               debug_only(const Type* bt2 = phi->bottom_type());
               assert(bt2->higher_equal_speculative(bt1), "must be consistent with type-flow");
               record_for_igvn(phi);
    @@ -2050,7 +2049,7 @@ void Parse::merge_memory_edges(MergeMemNode* n, int pnum, bool nophi) {
             base = phi;  // delay transforming it
           } else if (pnum == 1) {
             record_for_igvn(phi);
    -        p = _gvn.transform_no_reclaim(phi);
    +        p = _gvn.transform(phi);
           }
           mms.set_memory(p);// store back through the iterator
         }
    @@ -2058,7 +2057,7 @@ void Parse::merge_memory_edges(MergeMemNode* n, int pnum, bool nophi) {
       // Transform base last, in case we must fiddle with remerging.
       if (base != nullptr && pnum == 1) {
         record_for_igvn(base);
    -    m->set_base_memory( _gvn.transform_no_reclaim(base) );
    +    m->set_base_memory(_gvn.transform(base));
       }
     }
     
    diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp
    index cbf57c421e9..763227fa569 100644
    --- a/src/hotspot/share/opto/parse2.cpp
    +++ b/src/hotspot/share/opto/parse2.cpp
    @@ -2480,10 +2480,10 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest,
           const Type* tboth = tcon->join_speculative(tval);
           if (tboth == tval)  break;        // Nothing to gain.
           if (tcon->isa_int()) {
    -        ccast = new CastIINode(val, tboth);
    +        ccast = new CastIINode(control(), val, tboth);
           } else if (tcon == TypePtr::NULL_PTR) {
             // Cast to null, but keep the pointer identity temporarily live.
    -        ccast = new CastPPNode(val, tboth);
    +        ccast = new CastPPNode(control(), val, tboth);
           } else {
             const TypeF* tf = tcon->isa_float_constant();
             const TypeD* td = tcon->isa_double_constant();
    @@ -2514,7 +2514,6 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest,
         assert(tcc != tval && tcc->higher_equal(tval), "must improve");
         // Delay transform() call to allow recovery of pre-cast value
         // at the control merge.
    -    ccast->set_req(0, control());
         _gvn.set_type_bottom(ccast);
         record_for_igvn(ccast);
         cast = ccast;
    @@ -3537,7 +3536,7 @@ void Parse::do_one_bytecode() {
       }
     
     #ifndef PRODUCT
    -  constexpr int perBytecode = 5;
    +  constexpr int perBytecode = 6;
       if (C->should_print_igv(perBytecode)) {
         IdealGraphPrinter* printer = C->igv_printer();
         char buffer[256];
    diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
    index 8f9acc6e827..f7c1cfcfdb9 100644
    --- a/src/hotspot/share/opto/phaseX.cpp
    +++ b/src/hotspot/share/opto/phaseX.cpp
    @@ -670,17 +670,10 @@ Node* PhaseGVN::apply_ideal(Node* k, bool can_reshape) {
       return i;
     }
     
    -//------------------------------transform--------------------------------------
    -// Return a node which computes the same function as this node, but in a
    -// faster or cheaper fashion.
    -Node *PhaseGVN::transform( Node *n ) {
    -  return transform_no_reclaim(n);
    -}
    -
     //------------------------------transform--------------------------------------
     // Return a node which computes the same function as this node, but
     // in a faster or cheaper fashion.
    -Node *PhaseGVN::transform_no_reclaim(Node *n) {
    +Node* PhaseGVN::transform(Node* n) {
       NOT_PRODUCT( set_transforms(); )
     
       // Apply the Ideal call in a loop until it no longer applies
    @@ -692,7 +685,7 @@ Node *PhaseGVN::transform_no_reclaim(Node *n) {
         k = i;
     #ifdef ASSERT
         if (loop_count >= K + C->live_nodes()) {
    -      dump_infinite_loop_info(i, "PhaseGVN::transform_no_reclaim");
    +      dump_infinite_loop_info(i, "PhaseGVN::transform");
         }
     #endif
         i = apply_ideal(k, /*can_reshape=*/false);
    @@ -894,7 +887,7 @@ void PhaseIterGVN::verify_step(Node* n) {
     void PhaseIterGVN::trace_PhaseIterGVN(Node* n, Node* nn, const Type* oldtype) {
       const Type* newtype = type_or_null(n);
       if (nn != n || oldtype != newtype) {
    -    C->print_method(PHASE_AFTER_ITER_GVN_STEP, 4, n);
    +    C->print_method(PHASE_AFTER_ITER_GVN_STEP, 5, n);
       }
       if (TraceIterativeGVN) {
         uint wlsize = _worklist.size();
    @@ -1025,6 +1018,7 @@ void PhaseIterGVN::trace_PhaseIterGVN_verbose(Node* n, int num_processed) {
     void PhaseIterGVN::optimize() {
       DEBUG_ONLY(uint num_processed  = 0;)
       NOT_PRODUCT(init_verifyPhaseIterGVN();)
    +  NOT_PRODUCT(C->reset_igv_phase_iter(PHASE_AFTER_ITER_GVN_STEP);)
       C->print_method(PHASE_BEFORE_ITER_GVN, 3);
       if (StressIGVN) {
         shuffle_worklist();
    diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp
    index bf87d302c1e..9c463606686 100644
    --- a/src/hotspot/share/opto/phaseX.hpp
    +++ b/src/hotspot/share/opto/phaseX.hpp
    @@ -415,8 +415,8 @@ class PhaseGVN : public PhaseValues {
     public:
       // Return a node which computes the same function as this node, but
       // in a faster or cheaper fashion.
    -  Node  *transform( Node *n );
    -  Node  *transform_no_reclaim( Node *n );
    +  Node* transform(Node* n);
    +
       virtual void record_for_igvn(Node *n) {
         C->record_for_igvn(n);
       }
    diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp
    index aea0bfa2f0a..cfb4ef6f407 100644
    --- a/src/hotspot/share/opto/phasetype.hpp
    +++ b/src/hotspot/share/opto/phasetype.hpp
    @@ -28,53 +28,79 @@
     #include "utilities/bitMap.inline.hpp"
     
     #define COMPILER_PHASES(flags) \
    -  flags(BEFORE_STRINGOPTS,            "Before StringOpts") \
    -  flags(AFTER_STRINGOPTS,             "After StringOpts") \
    -  flags(BEFORE_REMOVEUSELESS,         "Before RemoveUseless") \
    -  flags(AFTER_PARSING,                "After Parsing") \
    -  flags(BEFORE_ITER_GVN,              "Before Iter GVN") \
    -  flags(ITER_GVN1,                    "Iter GVN 1") \
    -  flags(AFTER_ITER_GVN_STEP,          "After Iter GVN Step") \
    -  flags(AFTER_ITER_GVN,               "After Iter GVN") \
    -  flags(INCREMENTAL_INLINE_STEP,      "Incremental Inline Step") \
    -  flags(INCREMENTAL_INLINE_CLEANUP,   "Incremental Inline Cleanup") \
    -  flags(INCREMENTAL_INLINE,           "Incremental Inline") \
    -  flags(INCREMENTAL_BOXING_INLINE,    "Incremental Boxing Inline") \
    -  flags(EXPAND_VUNBOX,                "Expand VectorUnbox") \
    -  flags(SCALARIZE_VBOX,               "Scalarize VectorBox") \
    -  flags(INLINE_VECTOR_REBOX,          "Inline Vector Rebox Calls") \
    -  flags(EXPAND_VBOX,                  "Expand VectorBox") \
    -  flags(ELIMINATE_VBOX_ALLOC,         "Eliminate VectorBoxAllocate") \
    -  flags(ITER_GVN_BEFORE_EA,           "Iter GVN before EA") \
    -  flags(ITER_GVN_AFTER_VECTOR,        "Iter GVN after vector box elimination") \
    -  flags(BEFORE_BEAUTIFY_LOOPS,        "Before beautify loops") \
    -  flags(AFTER_BEAUTIFY_LOOPS,         "After beautify loops") \
    -  flags(BEFORE_CLOOPS,                "Before CountedLoop") \
    -  flags(AFTER_CLOOPS,                 "After CountedLoop") \
    -  flags(PHASEIDEAL_BEFORE_EA,         "PhaseIdealLoop before EA") \
    -  flags(AFTER_EA,                     "After Escape Analysis") \
    -  flags(ITER_GVN_AFTER_EA,            "Iter GVN after EA") \
    -  flags(ITER_GVN_AFTER_ELIMINATION,   "Iter GVN after eliminating allocations and locks") \
    -  flags(PHASEIDEALLOOP1,              "PhaseIdealLoop 1") \
    -  flags(PHASEIDEALLOOP2,              "PhaseIdealLoop 2") \
    -  flags(PHASEIDEALLOOP3,              "PhaseIdealLoop 3") \
    -  flags(CCP1,                         "PhaseCCP 1") \
    -  flags(ITER_GVN2,                    "Iter GVN 2") \
    -  flags(PHASEIDEALLOOP_ITERATIONS,    "PhaseIdealLoop iterations") \
    -  flags(MACRO_EXPANSION,              "Macro expand") \
    -  flags(BARRIER_EXPANSION,            "Barrier expand") \
    -  flags(OPTIMIZE_FINISHED,            "Optimize finished") \
    -  flags(BEFORE_MATCHING,              "Before matching") \
    -  flags(MATCHING,                     "After matching") \
    -  flags(GLOBAL_CODE_MOTION,           "Global code motion") \
    -  flags(MACH_ANALYSIS,                "After mach analysis") \
    -  flags(FINAL_CODE,                   "Final Code") \
    -  flags(END,                          "End") \
    -  flags(FAILURE,                      "Failure") \
    -  flags(SPLIT_INLINES_ARRAY,          "Split inlines array") \
    -  flags(SPLIT_INLINES_ARRAY_IGVN,     "IGVN after split inlines array") \
    -  flags(ALL,                          "All") \
    -  flags(DEBUG,                        "Debug")
    +  flags(BEFORE_STRINGOPTS,              "Before StringOpts") \
    +  flags(AFTER_STRINGOPTS,               "After StringOpts") \
    +  flags(BEFORE_REMOVEUSELESS,           "Before RemoveUseless") \
    +  flags(AFTER_PARSING,                  "After Parsing") \
    +  flags(BEFORE_ITER_GVN,                "Before Iter GVN") \
    +  flags(ITER_GVN1,                      "Iter GVN 1") \
    +  flags(AFTER_ITER_GVN_STEP,            "After Iter GVN Step") \
    +  flags(AFTER_ITER_GVN,                 "After Iter GVN") \
    +  flags(INCREMENTAL_INLINE_STEP,        "Incremental Inline Step") \
    +  flags(INCREMENTAL_INLINE_CLEANUP,     "Incremental Inline Cleanup") \
    +  flags(INCREMENTAL_INLINE,             "Incremental Inline") \
    +  flags(INCREMENTAL_BOXING_INLINE,      "Incremental Boxing Inline") \
    +  flags(EXPAND_VUNBOX,                  "Expand VectorUnbox") \
    +  flags(SCALARIZE_VBOX,                 "Scalarize VectorBox") \
    +  flags(INLINE_VECTOR_REBOX,            "Inline Vector Rebox Calls") \
    +  flags(EXPAND_VBOX,                    "Expand VectorBox") \
    +  flags(ELIMINATE_VBOX_ALLOC,           "Eliminate VectorBoxAllocate") \
    +  flags(ITER_GVN_BEFORE_EA,             "Iter GVN before EA") \
    +  flags(ITER_GVN_AFTER_VECTOR,          "Iter GVN after vector box elimination") \
    +  flags(BEFORE_BEAUTIFY_LOOPS,          "Before beautify loops") \
    +  flags(AFTER_BEAUTIFY_LOOPS,           "After beautify loops") \
    +  flags(BEFORE_LOOP_UNROLLING,          "Before Loop Unrolling") \
    +  flags(AFTER_LOOP_UNROLLING,           "After Loop Unrolling") \
    +  flags(BEFORE_SPLIT_IF,                "Before Split-If") \
    +  flags(AFTER_SPLIT_IF,                 "After Split-If") \
    +  flags(BEFORE_LOOP_PREDICATION_IC,     "Before Loop Predication IC") \
    +  flags(AFTER_LOOP_PREDICATION_IC,      "After Loop Predication IC") \
    +  flags(BEFORE_LOOP_PREDICATION_RC,     "Before Loop Predication RC") \
    +  flags(AFTER_LOOP_PREDICATION_RC,      "After Loop Predication RC") \
    +  flags(BEFORE_PARTIAL_PEELING,         "Before Partial Peeling") \
    +  flags(AFTER_PARTIAL_PEELING,          "After Partial Peeling") \
    +  flags(BEFORE_LOOP_PEELING,            "Before Loop Peeling") \
    +  flags(AFTER_LOOP_PEELING,             "After Loop Peeling") \
    +  flags(BEFORE_LOOP_UNSWITCHING,        "Before Loop Unswitching") \
    +  flags(AFTER_LOOP_UNSWITCHING,         "After Loop Unswitching") \
    +  flags(BEFORE_RANGE_CHECK_ELIMINATION, "Before Range Check Elimination") \
    +  flags(AFTER_RANGE_CHECK_ELIMINATION,  "After Range Check Elimination") \
    +  flags(BEFORE_PRE_MAIN_POST,           "Before Pre/Main/Post Loops") \
    +  flags(AFTER_PRE_MAIN_POST,            "After Pre/Main/Post Loops") \
    +  flags(SUPERWORD1_BEFORE_SCHEDULE,     "Superword 1, Before Schedule") \
    +  flags(SUPERWORD2_BEFORE_OUTPUT,       "Superword 2, Before Output") \
    +  flags(SUPERWORD3_AFTER_OUTPUT,        "Superword 3, After Output") \
    +  flags(BEFORE_CLOOPS,                  "Before CountedLoop") \
    +  flags(AFTER_CLOOPS,                   "After CountedLoop") \
    +  flags(PHASEIDEAL_BEFORE_EA,           "PhaseIdealLoop before EA") \
    +  flags(AFTER_EA,                       "After Escape Analysis") \
    +  flags(ITER_GVN_AFTER_EA,              "Iter GVN after EA") \
    +  flags(ITER_GVN_AFTER_ELIMINATION,     "Iter GVN after eliminating allocations and locks") \
    +  flags(PHASEIDEALLOOP1,                "PhaseIdealLoop 1") \
    +  flags(PHASEIDEALLOOP2,                "PhaseIdealLoop 2") \
    +  flags(PHASEIDEALLOOP3,                "PhaseIdealLoop 3") \
    +  flags(BEFORE_CCP1,                    "Before PhaseCCP 1") \
    +  flags(CCP1,                           "PhaseCCP 1") \
    +  flags(ITER_GVN2,                      "Iter GVN 2") \
    +  flags(PHASEIDEALLOOP_ITERATIONS,      "PhaseIdealLoop iterations") \
    +  flags(MACRO_EXPANSION,                "Macro expand") \
    +  flags(BARRIER_EXPANSION,              "Barrier expand") \
    +  flags(OPTIMIZE_FINISHED,              "Optimize finished") \
    +  flags(BEFORE_MATCHING,                "Before matching") \
    +  flags(MATCHING,                       "After matching") \
    +  flags(GLOBAL_CODE_MOTION,             "Global code motion") \
    +  flags(REGISTER_ALLOCATION,            "Register Allocation") \
    +  flags(BLOCK_ORDERING,                 "Block Ordering") \
    +  flags(PEEPHOLE,                       "Peephole") \
    +  flags(POSTALLOC_EXPAND,               "Post-Allocation Expand") \
    +  flags(MACH_ANALYSIS,                  "After mach analysis") \
    +  flags(FINAL_CODE,                     "Final Code") \
    +  flags(END,                            "End") \
    +  flags(FAILURE,                        "Failure") \
    +  flags(SPLIT_INLINES_ARRAY,            "Split inlines array") \
    +  flags(SPLIT_INLINES_ARRAY_IGVN,       "IGVN after split inlines array") \
    +  flags(ALL,                            "All") \
    +  flags(DEBUG,                          "Debug")
     
     #define table_entry(name, description) PHASE_##name,
     enum CompilerPhaseType {
    diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp
    index 77fb62daa28..8be5c5f8dc8 100644
    --- a/src/hotspot/share/opto/split_if.cpp
    +++ b/src/hotspot/share/opto/split_if.cpp
    @@ -592,12 +592,6 @@ void PhaseIdealLoop::handle_use( Node *use, Node *def, small_cache *cache, Node
     // Found an If getting its condition-code input from a Phi in the same block.
     // Split thru the Region.
     void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, RegionNode** new_true_region) {
    -  if (PrintOpto && VerifyLoopOptimizations) {
    -    tty->print_cr("Split-if");
    -  }
    -  if (TraceLoopOpts) {
    -    tty->print_cr("SplitIf");
    -  }
     
       C->set_major_progress();
       RegionNode *region = iff->in(0)->as_Region();
    diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp
    index dd3f1d10dee..4b1d9e54572 100644
    --- a/src/hotspot/share/opto/superword.cpp
    +++ b/src/hotspot/share/opto/superword.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -557,14 +557,22 @@ bool SuperWord::SLP_extract() {
       // Attempt vectorization
       find_adjacent_refs();
     
    -  if (align_to_ref() == nullptr) {
    -    return false; // Did not find memory reference to align vectors
    +  if (_packset.length() == 0) {
    +#ifndef PRODUCT
    +    if (TraceSuperWord) {
    +      tty->print_cr("\nNo pair packs generated, abort SuperWord.");
    +      tty->cr();
    +    }
    +#endif
    +    return false;
       }
     
       extend_packlist();
     
       combine_packs();
     
    +  filter_packs_for_alignment();
    +
       construct_my_pack_map();
     
       filter_packs();
    @@ -578,9 +586,9 @@ bool SuperWord::SLP_extract() {
     
     //------------------------------find_adjacent_refs---------------------------
     // Find the adjacent memory references and create pack pairs for them.
    -// This is the initial set of packs that will then be extended by
    -// following use->def and def->use links.  The align positions are
    -// assigned relative to the reference "align_to_ref"
    +// We can find adjacent memory references by comparing their relative
    +// alignment. Whether the final vectors can be aligned is determined later
    +// once all vectors are extended and combined.
     void SuperWord::find_adjacent_refs() {
       // Get list of memory operations
       Node_List memops;
    @@ -598,25 +606,22 @@ void SuperWord::find_adjacent_refs() {
         tty->print_cr("\nfind_adjacent_refs found %d memops", memops.size());
       }
     
    -  Node_List align_to_refs;
       int max_idx;
    -  int best_iv_adjustment = 0;
    -  MemNode* best_align_to_mem_ref = nullptr;
    +
    +  // Take the first mem_ref as the reference to align to. The pre-loop trip count is
    +  // modified to align this reference to a vector-aligned address. If strict alignment
    +  // is required, we may change the reference later (see filter_packs_for_alignment()).
    +  MemNode* align_to_mem_ref = nullptr;
     
       while (memops.size() != 0) {
         // Find a memory reference to align to.
         MemNode* mem_ref = find_align_to_ref(memops, max_idx);
         if (mem_ref == nullptr) break;
    -    align_to_refs.push(mem_ref);
         int iv_adjustment = get_iv_adjustment(mem_ref);
     
    -    if (best_align_to_mem_ref == nullptr) {
    -      // Set memory reference which is the best from all memory operations
    -      // to be used for alignment. The pre-loop trip count is modified to align
    -      // this reference to a vector-aligned address.
    -      best_align_to_mem_ref = mem_ref;
    -      best_iv_adjustment = iv_adjustment;
    -      NOT_PRODUCT(find_adjacent_refs_trace_1(best_align_to_mem_ref, best_iv_adjustment);)
    +    if (align_to_mem_ref == nullptr) {
    +      align_to_mem_ref = mem_ref;
    +      set_align_to_ref(align_to_mem_ref);
         }
     
         VPointer align_to_ref_p(mem_ref, phase(), lpt(), nullptr, false);
    @@ -633,90 +638,26 @@ void SuperWord::find_adjacent_refs() {
           }
         }
     
    -    if (mem_ref_has_no_alignment_violation(mem_ref, iv_adjustment, align_to_ref_p,
    -                                           best_align_to_mem_ref, best_iv_adjustment,
    -                                           align_to_refs)) {
    -      // Create initial pack pairs of memory operations for which alignment was set.
    -      for (uint i = 0; i < memops.size(); i++) {
    -        Node* s1 = memops.at(i);
    -        int align = alignment(s1);
    -        if (align == top_align) continue;
    -        for (uint j = 0; j < memops.size(); j++) {
    -          Node* s2 = memops.at(j);
    -          if (alignment(s2) == top_align) continue;
    -          if (s1 != s2 && are_adjacent_refs(s1, s2)) {
    -            if (stmts_can_pack(s1, s2, align)) {
    -              Node_List* pair = new Node_List();
    -              pair->push(s1);
    -              pair->push(s2);
    -              if (!_do_vector_loop || same_origin_idx(s1, s2)) {
    -                _packset.append(pair);
    -              }
    -            }
    -          }
    -        }
    -      }
    -    } else {
    -      // Cannot create pairs for mem_ref. Reject all related memops forever.
    -
    -      // First, remove remaining memory ops of the same memory slice from the list.
    -      for (int i = memops.size() - 1; i >= 0; i--) {
    -        MemNode* s = memops.at(i)->as_Mem();
    -        if (same_memory_slice(s, mem_ref) || same_velt_type(s, mem_ref)) {
    -          memops.remove(i);
    -        }
    -      }
    -
    -      // Second, remove already constructed packs of the same memory slice.
    -      for (int i = _packset.length() - 1; i >= 0; i--) {
    -        Node_List* p = _packset.at(i);
    -        MemNode* s = p->at(0)->as_Mem();
    -        if (same_memory_slice(s, mem_ref) || same_velt_type(s, mem_ref)) {
    -          remove_pack_at(i);
    -        }
    -      }
    -
    -      // If needed find the best memory reference for loop alignment again.
    -      if (same_memory_slice(mem_ref, best_align_to_mem_ref) || same_velt_type(mem_ref, best_align_to_mem_ref)) {
    -        // Put memory ops from remaining packs back on memops list for
    -        // the best alignment search.
    -        uint orig_msize = memops.size();
    -        for (int i = 0; i < _packset.length(); i++) {
    -          Node_List* p = _packset.at(i);
    -          MemNode* s = p->at(0)->as_Mem();
    -          assert(!same_velt_type(s, mem_ref), "sanity");
    -          memops.push(s);
    -        }
    -        best_align_to_mem_ref = find_align_to_ref(memops, max_idx);
    -        if (best_align_to_mem_ref == nullptr) {
    -          if (TraceSuperWord) {
    -            tty->print_cr("SuperWord::find_adjacent_refs(): best_align_to_mem_ref == nullptr");
    -          }
    -          // best_align_to_mem_ref will be used for adjusting the pre-loop limit in
    -          // SuperWord::align_initial_loop_index. Find one with the biggest vector size,
    -          // smallest data size and smallest iv offset from memory ops from remaining packs.
    -          if (_packset.length() > 0) {
    -            if (orig_msize == 0) {
    -              best_align_to_mem_ref = memops.at(max_idx)->as_Mem();
    -            } else {
    -              for (uint i = 0; i < orig_msize; i++) {
    -                memops.remove(0);
    -              }
    -              best_align_to_mem_ref = find_align_to_ref(memops, max_idx);
    -              assert(best_align_to_mem_ref == nullptr, "sanity");
    -              best_align_to_mem_ref = memops.at(max_idx)->as_Mem();
    +    // Create initial pack pairs of memory operations for which alignment was set.
    +    for (uint i = 0; i < memops.size(); i++) {
    +      Node* s1 = memops.at(i);
    +      int align = alignment(s1);
    +      if (align == top_align) continue;
    +      for (uint j = 0; j < memops.size(); j++) {
    +        Node* s2 = memops.at(j);
    +        if (alignment(s2) == top_align) continue;
    +        if (s1 != s2 && are_adjacent_refs(s1, s2)) {
    +          if (stmts_can_pack(s1, s2, align)) {
    +            Node_List* pair = new Node_List();
    +            pair->push(s1);
    +            pair->push(s2);
    +            if (!_do_vector_loop || same_origin_idx(s1, s2)) {
    +              _packset.append(pair);
                 }
    -            assert(best_align_to_mem_ref != nullptr, "sanity");
               }
    -          break;
             }
    -        best_iv_adjustment = get_iv_adjustment(best_align_to_mem_ref);
    -        NOT_PRODUCT(find_adjacent_refs_trace_1(best_align_to_mem_ref, best_iv_adjustment);)
    -        // Restore list.
    -        while (memops.size() > orig_msize)
    -          (void)memops.pop();
           }
    -    } // unaligned memory accesses
    +    }
     
         // Remove used mem nodes.
         for (int i = memops.size() - 1; i >= 0; i--) {
    @@ -725,66 +666,17 @@ void SuperWord::find_adjacent_refs() {
             memops.remove(i);
           }
         }
    +  } // while (memops.size() != 0)
     
    -  } // while (memops.size() != 0
    -  set_align_to_ref(best_align_to_mem_ref);
    +  assert(_packset.is_empty() || align_to_mem_ref != nullptr,
    +         "packset empty or we find the alignment reference");
     
    +#ifndef PRODUCT
       if (TraceSuperWord) {
         tty->print_cr("\nAfter find_adjacent_refs");
         print_packset();
       }
    -}
    -
    -#ifndef PRODUCT
    -void SuperWord::find_adjacent_refs_trace_1(Node* best_align_to_mem_ref, int best_iv_adjustment) {
    -  if (is_trace_adjacent()) {
    -    tty->print("SuperWord::find_adjacent_refs best_align_to_mem_ref = %d, best_iv_adjustment = %d",
    -       best_align_to_mem_ref->_idx, best_iv_adjustment);
    -       best_align_to_mem_ref->dump();
    -  }
    -}
     #endif
    -
    -// If strict memory alignment is required (vectors_should_be_aligned), then check if
    -// mem_ref is aligned with best_align_to_mem_ref.
    -bool SuperWord::mem_ref_has_no_alignment_violation(MemNode* mem_ref, int iv_adjustment, VPointer& align_to_ref_p,
    -                                                   MemNode* best_align_to_mem_ref, int best_iv_adjustment,
    -                                                   Node_List &align_to_refs) {
    -  if (!vectors_should_be_aligned()) {
    -    // Alignment is not required by the hardware. No violation possible.
    -    return true;
    -  }
    -
    -  // All vectors need to be memory aligned, modulo their vector_width. This is more strict
    -  // than the hardware probably requires. Most hardware at most requires 4-byte alignment.
    -  //
    -  // In the pre-loop, we align best_align_to_mem_ref to its vector_length. To ensure that
    -  // all mem_ref's are memory aligned modulo their vector_width, we only need to check that
    -  // they are all aligned to best_align_to_mem_ref, modulo their vector_width. For that,
    -  // we check the following 3 conditions.
    -
    -  // (1) All packs are aligned with best_align_to_mem_ref.
    -  if (memory_alignment(mem_ref, best_iv_adjustment) != 0) {
    -    return false;
    -  }
    -  // (2) All other vectors have vector_size less or equal to that of best_align_to_mem_ref.
    -  int vw = vector_width(mem_ref);
    -  int vw_best = vector_width(best_align_to_mem_ref);
    -  if (vw > vw_best) {
    -    // We only align to vector_width of best_align_to_mem_ref during pre-loop.
    -    // A mem_ref with a larger vector_width might thus not be vector_width aligned.
    -    return false;
    -  }
    -  // (3) Ensure that all vectors have the same invariant. We model memory accesses like this
    -  //     address = base + k*iv + constant [+ invar]
    -  //     memory_alignment ignores the invariant.
    -  VPointer p2(best_align_to_mem_ref, phase(), lpt(), nullptr, false);
    -  if (!align_to_ref_p.invar_equals(p2)) {
    -    // Do not vectorize memory accesses with different invariants
    -    // if unaligned memory accesses are not allowed.
    -    return false;
    -  }
    -  return true;
     }
     
     //------------------------------find_align_to_ref---------------------------
    @@ -798,12 +690,6 @@ MemNode* SuperWord::find_align_to_ref(Node_List &memops, int &idx) {
       for (uint i = 0; i < memops.size(); i++) {
         MemNode* s1 = memops.at(i)->as_Mem();
         VPointer p1(s1, phase(), lpt(), nullptr, false);
    -    // Only discard unalignable memory references if vector memory references
    -    // should be aligned on this platform.
    -    if (vectors_should_be_aligned() && !ref_is_alignable(p1)) {
    -      *cmp_ct.adr_at(i) = 0;
    -      continue;
    -    }
         for (uint j = i+1; j < memops.size(); j++) {
           MemNode* s2 = memops.at(j)->as_Mem();
           if (isomorphic(s1, s2)) {
    @@ -892,95 +778,6 @@ MemNode* SuperWord::find_align_to_ref(Node_List &memops, int &idx) {
       return nullptr;
     }
     
    -//------------------span_works_for_memory_size-----------------------------
    -static bool span_works_for_memory_size(MemNode* mem, int span, int mem_size, int offset) {
    -  bool span_matches_memory = false;
    -  if ((mem_size == type2aelembytes(T_BYTE) || mem_size == type2aelembytes(T_SHORT))
    -    && ABS(span) == type2aelembytes(T_INT)) {
    -    // There is a mismatch on span size compared to memory.
    -    for (DUIterator_Fast jmax, j = mem->fast_outs(jmax); j < jmax; j++) {
    -      Node* use = mem->fast_out(j);
    -      if (!VectorNode::is_type_transition_to_int(use)) {
    -        return false;
    -      }
    -    }
    -    // If all uses transition to integer, it means that we can successfully align even on mismatch.
    -    return true;
    -  }
    -  else {
    -    span_matches_memory = ABS(span) == mem_size;
    -  }
    -  return span_matches_memory && (ABS(offset) % mem_size) == 0;
    -}
    -
    -//------------------------------ref_is_alignable---------------------------
    -// Can the preloop align the reference to position zero in the vector?
    -bool SuperWord::ref_is_alignable(VPointer& p) {
    -  if (!p.has_iv()) {
    -    return true;   // no induction variable
    -  }
    -  CountedLoopEndNode* pre_end = lp()->pre_loop_end();
    -  assert(pre_end->stride_is_con(), "pre loop stride is constant");
    -  int preloop_stride = pre_end->stride_con();
    -
    -  int span = preloop_stride * p.scale_in_bytes();
    -  int mem_size = p.memory_size();
    -  int offset   = p.offset_in_bytes();
    -  // Stride one accesses are alignable if offset is aligned to memory operation size.
    -  // Offset can be unaligned when UseUnalignedAccesses is used.
    -  if (span_works_for_memory_size(p.mem(), span, mem_size, offset)) {
    -    return true;
    -  }
    -  // If the initial offset from start of the object is computable,
    -  // check if the pre-loop can align the final offset accordingly.
    -  //
    -  // In other words: Can we find an i such that the offset
    -  // after i pre-loop iterations is aligned to vw?
    -  //   (init_offset + pre_loop) % vw == 0              (1)
    -  // where
    -  //   pre_loop = i * span
    -  // is the number of bytes added to the offset by i pre-loop iterations.
    -  //
    -  // For this to hold we need pre_loop to increase init_offset by
    -  //   pre_loop = vw - (init_offset % vw)
    -  //
    -  // This is only possible if pre_loop is divisible by span because each
    -  // pre-loop iteration increases the initial offset by 'span' bytes:
    -  //   (vw - (init_offset % vw)) % span == 0
    -  //
    -  int vw = vector_width_in_bytes(p.mem());
    -  assert(vw > 1, "sanity");
    -  Node* init_nd = pre_end->init_trip();
    -  if (init_nd->is_Con() && p.invar() == nullptr) {
    -    int init = init_nd->bottom_type()->is_int()->get_con();
    -    int init_offset = init * p.scale_in_bytes() + offset;
    -    if (init_offset < 0) { // negative offset from object start?
    -      return false;        // may happen in dead loop
    -    }
    -    if (vw % span == 0) {
    -      // If vm is a multiple of span, we use formula (1).
    -      if (span > 0) {
    -        return (vw - (init_offset % vw)) % span == 0;
    -      } else {
    -        assert(span < 0, "nonzero stride * scale");
    -        return (init_offset % vw) % -span == 0;
    -      }
    -    } else if (span % vw == 0) {
    -      // If span is a multiple of vw, we can simplify formula (1) to:
    -      //   (init_offset + i * span) % vw == 0
    -      //     =>
    -      //   (init_offset % vw) + ((i * span) % vw) == 0
    -      //     =>
    -      //   init_offset % vw == 0
    -      //
    -      // Because we add a multiple of vw to the initial offset, the final
    -      // offset is a multiple of vw if and only if init_offset is a multiple.
    -      //
    -      return (init_offset % vw) == 0;
    -    }
    -  }
    -  return false;
    -}
     //---------------------------get_vw_bytes_special------------------------
     int SuperWord::get_vw_bytes_special(MemNode* s) {
       // Get the vector width in bytes.
    @@ -1026,10 +823,6 @@ int SuperWord::get_iv_adjustment(MemNode* mem_ref) {
         // several iterations are needed to align memory operations in main-loop even
         // if offset is 0.
         int iv_adjustment_in_bytes = (stride_sign * vw - (offset % vw));
    -    // iv_adjustment_in_bytes must be a multiple of elt_size if vector memory
    -    // references should be aligned on this platform.
    -    assert((ABS(iv_adjustment_in_bytes) % elt_size) == 0 || !vectors_should_be_aligned(),
    -           "(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size);
         iv_adjustment = iv_adjustment_in_bytes/elt_size;
       } else {
         // This memory op is not dependent on iv (scale == 0)
    @@ -1707,6 +1500,12 @@ int SuperWord::unpack_cost(int ct) { return ct; }
     //------------------------------combine_packs---------------------------
     // Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last
     void SuperWord::combine_packs() {
    +#ifdef ASSERT
    +  for (int i = 0; i < _packset.length(); i++) {
    +    assert(_packset.at(i) != nullptr, "no nullptr in packset");
    +  }
    +#endif
    +
       bool changed = true;
       // Combine packs regardless max vector size.
       while (changed) {
    @@ -1802,18 +1601,123 @@ void SuperWord::combine_packs() {
         }
       }
     
    -  // Compress list.
    -  for (int i = _packset.length() - 1; i >= 0; i--) {
    -    Node_List* p1 = _packset.at(i);
    -    if (p1 == nullptr) {
    -      _packset.remove_at(i);
    -    }
    -  }
    +  // Remove all nullptr from packset
    +  compress_packset();
     
    +#ifndef PRODUCT
       if (TraceSuperWord) {
         tty->print_cr("\nAfter combine_packs");
         print_packset();
       }
    +#endif
    +}
    +
    +// Find the set of alignment solutions for load/store pack.
    +const AlignmentSolution* SuperWord::pack_alignment_solution(Node_List* pack) {
    +  assert(pack != nullptr && (pack->at(0)->is_Load() || pack->at(0)->is_Store()), "only load/store packs");
    +
    +  const MemNode* mem_ref = pack->at(0)->as_Mem();
    +  VPointer mem_ref_p(mem_ref, phase(), lpt(), nullptr, false);
    +  const CountedLoopEndNode* pre_end = lp()->pre_loop_end();
    +  assert(pre_end->stride_is_con(), "pre loop stride is constant");
    +
    +  AlignmentSolver solver(pack->at(0)->as_Mem(),
    +                         pack->size(),
    +                         mem_ref_p.base(),
    +                         mem_ref_p.offset_in_bytes(),
    +                         mem_ref_p.invar(),
    +                         mem_ref_p.invar_factor(),
    +                         mem_ref_p.scale_in_bytes(),
    +                         pre_end->init_trip(),
    +                         pre_end->stride_con(),
    +                         iv_stride()
    +                         DEBUG_ONLY(COMMA is_trace_align_vector()));
    +  return solver.solve();
    +}
    +
    +// Ensure all packs are aligned, if AlignVector is on.
    +// Find an alignment solution: find the set of pre_iter that memory align all packs.
    +// Start with the maximal set (pre_iter >= 0) and filter it with the constraints
    +// that the packs impose. Remove packs that do not have a compatible solution.
    +void SuperWord::filter_packs_for_alignment() {
    +  // We do not need to filter if no alignment is required.
    +  if (!vectors_should_be_aligned()) {
    +    return;
    +  }
    +
    +#ifndef PRODUCT
    +  if (TraceSuperWord || is_trace_align_vector()) {
    +    tty->print_cr("\nfilter_packs_for_alignment:");
    +  }
    +#endif
    +
    +  ResourceMark rm;
    +
    +  // Start with trivial (unconstrained) solution space
    +  AlignmentSolution const* current = new TrivialAlignmentSolution();
    +  int mem_ops_count = 0;
    +  int mem_ops_rejected = 0;
    +  for (int i = 0; i < _packset.length(); i++) {
    +    Node_List* p = _packset.at(i);
    +    if (p != nullptr) {
    +      if (p->at(0)->is_Load() || p->at(0)->is_Store()) {
    +        mem_ops_count++;
    +        // Find solution for pack p, and filter with current solution.
    +        const AlignmentSolution* s = pack_alignment_solution(p);
    +        const AlignmentSolution* intersect = current->filter(s);
    +
    +#ifndef PRODUCT
    +        if (is_trace_align_vector()) {
    +          tty->print("  solution for pack:         ");
    +          s->print();
    +          tty->print("  intersection with current: ");
    +          intersect->print();
    +        }
    +#endif
    +
    +        if (intersect->is_empty()) {
    +          // Solution failed or is not compatible, remove pack i.
    +          _packset.at_put(i, nullptr);
    +          mem_ops_rejected++;
    +        } else {
    +          // Solution is compatible.
    +          current = intersect;
    +        }
    +      }
    +    }
    +  }
    +
    +#ifndef PRODUCT
    +  if (TraceSuperWord || is_trace_align_vector()) {
    +    tty->print("\n final solution: ");
    +    current->print();
    +    tty->print_cr(" rejected mem_ops packs: %d of %d", mem_ops_rejected, mem_ops_count);
    +    tty->cr();
    +  }
    +#endif
    +
    +  assert(!current->is_empty(), "solution must be non-empty");
    +  if (current->is_constrained()) {
    +    // Solution is constrained (not trivial)
    +    // -> must change pre-limit to achieve alignment
    +    set_align_to_ref(current->as_constrained()->mem_ref());
    +  }
    +
    +  // Remove all nullptr from packset
    +  compress_packset();
    +}
    +
    +// Compress packset, such that it has no nullptr entries
    +void SuperWord::compress_packset() {
    +  int j = 0;
    +  for (int i = 0; i < _packset.length(); i++) {
    +    Node_List* p = _packset.at(i);
    +    if (p != nullptr) {
    +      _packset.at_put(j, p);
    +      j++;
    +    }
    +  }
    +  _packset.trunc_to(j);
     }
     
     //-----------------------------construct_my_pack_map--------------------------
    @@ -2381,6 +2285,9 @@ void SuperWord::schedule() {
       }
     #endif
     
    +  CountedLoopNode* cl = lpt()->_head->as_CountedLoop();
    +  _phase->C->print_method(PHASE_SUPERWORD1_BEFORE_SCHEDULE, 4, cl);
    +
       // (4) Use the memops_schedule to re-order the memops in all slices.
       schedule_reorder_memops(memops_schedule);
     }
    @@ -2488,10 +2395,9 @@ bool SuperWord::output() {
         lpt()->dump_head();
       }
     #endif
    +  _phase->C->print_method(PHASE_SUPERWORD2_BEFORE_OUTPUT, 4, cl);
     
    -  // Ensure main loop's initial value is properly aligned
    -  //  (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0
    -  align_initial_loop_index(align_to_ref());
    +  adjust_pre_loop_limit_to_align_main_loop_vectors();
     
       // Insert extract (unpack) operations for scalar uses
       for (int i = 0; i < _packset.length(); i++) {
    @@ -2764,6 +2670,17 @@ bool SuperWord::output() {
             return false; // bailout
           }
     
    +#ifdef ASSERT
    +      // Mark Load/Store Vector for alignment verification
    +      if (VerifyAlignVector) {
    +        if (vn->Opcode() == Op_LoadVector) {
    +          vn->as_LoadVector()->set_must_verify_alignment();
    +        } else if (vn->Opcode() == Op_StoreVector) {
    +          vn->as_StoreVector()->set_must_verify_alignment();
    +        }
    +      }
    +#endif
    +
           _block.at_put(i, vn);
           _igvn.register_new_node_with_optimizer(vn);
           _phase->set_ctrl(vn, _phase->get_ctrl(first));
    @@ -2808,6 +2725,8 @@ bool SuperWord::output() {
         }
       }
     
    +  _phase->C->print_method(PHASE_SUPERWORD3_AFTER_OUTPUT, 4, cl);
    +
       return true;
     }
     
    @@ -3547,167 +3466,337 @@ LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) {
       return dep;
     }
     
    +#define TRACE_ALIGN_VECTOR_NODE(node) { \
    +  DEBUG_ONLY(                           \
    +    if (is_trace_align_vector()) {      \
    +      tty->print("  " #node ": ");      \
    +      node->dump();                     \
    +    }                                   \
    +  )                                     \
    +}                                       \
    +
    +// Ensure that the main loop vectors are aligned by adjusting the pre loop limit. We memory-align
    +// the address of "align_to_ref" to the maximal possible vector width. We adjust the pre-loop
    +// iteration count by adjusting the pre-loop limit.
    +void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() {
    +  const MemNode* align_to_ref = _align_to_ref;
    +  assert(align_to_ref != nullptr, "align_to_ref must be set");
    +  assert(lp()->is_main_loop(), "can only do alignment for main loop");
     
    -//----------------------------align_initial_loop_index---------------------------
    -// Adjust pre-loop limit so that in main loop, a load/store reference
    -// to align_to_ref will be a position zero in the vector.
    -//   (iv + k) mod vector_align == 0
    -void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
    -  assert(lp()->is_main_loop(), "");
    -  CountedLoopEndNode* pre_end = lp()->pre_loop_end();
    -  Node* pre_opaq1 = pre_end->limit();
    -  assert(pre_opaq1->Opcode() == Op_Opaque1, "");
    -  Opaque1Node* pre_opaq = (Opaque1Node*)pre_opaq1;
    -  Node* lim0 = pre_opaq->in(1);
    +  // The opaque node for the limit, where we adjust the input
    +  Opaque1Node* pre_opaq = lp()->pre_loop_end()->limit()->as_Opaque1();
     
    -  // Where we put new limit calculations
    +  // Current pre-loop limit.
    +  Node* old_limit = pre_opaq->in(1);
    +
    +  // Where we put new limit calculations.
       Node* pre_ctrl = lp()->pre_loop_head()->in(LoopNode::EntryControl);
     
    -  // Ensure the original loop limit is available from the
    -  // pre-loop Opaque1 node.
    +  // Ensure the original loop limit is available from the pre-loop Opaque1 node.
       Node* orig_limit = pre_opaq->original_loop_limit();
       assert(orig_limit != nullptr && _igvn.type(orig_limit) != Type::TOP, "");
     
       VPointer align_to_ref_p(align_to_ref, phase(), lpt(), nullptr, false);
       assert(align_to_ref_p.valid(), "sanity");
     
    -  // Given:
    -  //     lim0 == original pre loop limit
    -  //     V == v_align (power of 2)
    -  //     invar == extra invariant piece of the address expression
    -  //     e == offset [ +/- invar ]
    +  // For the main-loop, we want the address of align_to_ref to be memory aligned
    +  // with some alignment width (aw, a power of 2). When we enter the main-loop,
    +  // we know that iv is equal to the pre-loop limit. If we adjust the pre-loop
    +  // limit by executing adjust_pre_iter many extra iterations, we can change the
    +  // alignment of the address.
       //
    -  // When reassociating expressions involving '%' the basic rules are:
    -  //     (a - b) % k == 0   =>  a % k == b % k
    -  // and:
    -  //     (a + b) % k == 0   =>  a % k == (k - b) % k
    +  //   adr = base + offset + invar + scale * iv                               (1)
    +  //   adr % aw = 0                                                           (2)
       //
    -  // For stride > 0 && scale > 0,
    -  //   Derive the new pre-loop limit "lim" such that the two constraints:
    -  //     (1) lim = lim0 + N           (where N is some positive integer < V)
    -  //     (2) (e + lim) % V == 0
    -  //   are true.
    +  // Note, that we are defining the modulo operator "%" such that the remainder is
    +  // always positive, see AlignmentSolution::mod(i, q). Since we are only computing
    +  // modulo with powers of 2, we can instead simply use the last log2(q) bits of
    +  // a number i, to get "i % q". This is performed with a bitmask.
       //
    -  //   Substituting (1) into (2),
    -  //     (e + lim0 + N) % V == 0
    -  //   solve for N:
    -  //     N = (V - (e + lim0)) % V
    -  //   substitute back into (1), so that new limit
    -  //     lim = lim0 + (V - (e + lim0)) % V
    +  // The limit of the pre-loop needs to be adjusted:
       //
    -  // For stride > 0 && scale < 0
    -  //   Constraints:
    -  //     lim = lim0 + N
    -  //     (e - lim) % V == 0
    -  //   Solving for lim:
    -  //     (e - lim0 - N) % V == 0
    -  //     N = (e - lim0) % V
    -  //     lim = lim0 + (e - lim0) % V
    +  //   old_limit:       current pre-loop limit
    +  //   new_limit:       new pre-loop limit
    +  //   adjust_pre_iter: additional pre-loop iterations for alignment adjustment
       //
    -  // For stride < 0 && scale > 0
    -  //   Constraints:
    -  //     lim = lim0 - N
    -  //     (e + lim) % V == 0
    -  //   Solving for lim:
    -  //     (e + lim0 - N) % V == 0
    -  //     N = (e + lim0) % V
    -  //     lim = lim0 - (e + lim0) % V
    +  // We want to find adjust_pre_iter, such that the address is aligned when entering
    +  // the main-loop:
       //
    -  // For stride < 0 && scale < 0
    -  //   Constraints:
    -  //     lim = lim0 - N
    -  //     (e - lim) % V == 0
    -  //   Solving for lim:
    -  //     (e - lim0 + N) % V == 0
    -  //     N = (V - (e - lim0)) % V
    -  //     lim = lim0 - (V - (e - lim0)) % V
    -
    -  int vw = vector_width_in_bytes(align_to_ref);
    -  int stride   = iv_stride();
    -  int scale    = align_to_ref_p.scale_in_bytes();
    -  int elt_size = align_to_ref_p.memory_size();
    -  int v_align  = vw / elt_size;
    -  assert(v_align > 1, "sanity");
    -  int offset   = align_to_ref_p.offset_in_bytes() / elt_size;
    -  Node *offsn  = _igvn.intcon(offset);
    -
    -  Node *e = offsn;
    -  if (align_to_ref_p.invar() != nullptr) {
    -    // incorporate any extra invariant piece producing (offset +/- invar) >>> log2(elt)
    -    Node* log2_elt = _igvn.intcon(exact_log2(elt_size));
    -    Node* invar = align_to_ref_p.invar();
    +  //   iv = new_limit = old_limit + adjust_pre_iter                           (3a, stride > 0)
    +  //   iv = new_limit = old_limit - adjust_pre_iter                           (3b, stride < 0)
    +  //
    +  // We define boi as:
    +  //
    +  //   boi = base + offset + invar                                            (4)
    +  //
    +  // And now we can simplify the address using (1), (3), and (4):
    +  //
    +  //   adr = boi + scale * new_limit
    +  //   adr = boi + scale * (old_limit + adjust_pre_iter)                      (5a, stride > 0)
    +  //   adr = boi + scale * (old_limit - adjust_pre_iter)                      (5b, stride < 0)
    +  //
    +  // And hence we can restate (2) with (5), and solve the equation for adjust_pre_iter:
    +  //
    +  //   (boi + scale * (old_limit + adjust_pre_iter) % aw = 0                  (6a, stride > 0)
    +  //   (boi + scale * (old_limit - adjust_pre_iter) % aw = 0                  (6b, stride < 0)
    +  //
    +  // In most cases, scale is the element size, for example:
    +  //
    +  //   for (i = 0; i < a.length; i++) { a[i] = ...; }
    +  //
    +  // It is thus reasonable to assume that both abs(scale) and abs(stride) are
    +  // strictly positive powers of 2. Further, they can be assumed to be non-zero,
    +  // otherwise the address does not depend on iv, and the alignment cannot be
    +  // affected by adjusting the pre-loop limit.
    +  //
    +  // Further, if abs(scale) >= aw, then adjust_pre_iter has no effect on alignment, and
    +  // we are not able to affect the alignment at all. Hence, we require abs(scale) < aw.
    +  //
    +  // Moreover, for alignment to be achievable, boi must be a multiple of scale. If strict
    +  // alignment is required (i.e. -XX:+AlignVector), this is guaranteed by the filtering
    +  // done with the AlignmentSolver / AlignmentSolution. If strict alignment is not
    +  // required, then alignment is still preferable for performance, but not necessary.
    +  // In many cases boi will be a multiple of scale, but if it is not, then the adjustment
    +  // does not guarantee alignment, but the code is still correct.
    +  //
    +  // Hence, in what follows we assume that boi is a multiple of scale, and in fact all
    +  // terms in (6) are multiples of scale. Therefore we divide all terms by scale:
    +  //
    +  //   AW = aw / abs(scale)            (power of 2)                           (7)
    +  //   BOI = boi / abs(scale)                                                 (8)
    +  //
    +  // and restate (6), using (7) and (8), i.e. we divide (6) by abs(scale):
    +  //
    +  //   (BOI + sign(scale) * (old_limit + adjust_pre_iter) % AW = 0           (9a, stride > 0)
    +  //   (BOI + sign(scale) * (old_limit - adjust_pre_iter) % AW = 0           (9b, stride < 0)
    +  //
    +  //   where: sign(scale) = scale / abs(scale) = (scale > 0 ? 1 : -1)
    +  //
    +  // Note, (9) allows for periodic solutions of adjust_pre_iter, with periodicity AW.
    +  // But we would like to spend as few iterations in the pre-loop as possible,
    +  // hence we want the smallest adjust_pre_iter, and so:
    +  //
    +  //   0 <= adjust_pre_iter < AW                                              (10)
    +  //
    +  // We solve (9) for adjust_pre_iter, in the following 4 cases:
    +  //
    +  // Case A: scale > 0 && stride > 0 (i.e. sign(scale) =  1)
    +  //   (BOI + old_limit + adjust_pre_iter) % AW = 0
    +  //   adjust_pre_iter = (-BOI - old_limit) % AW                              (11a)
    +  //
    +  // Case B: scale < 0 && stride > 0 (i.e. sign(scale) = -1)
    +  //   (BOI - old_limit - adjust_pre_iter) % AW = 0
    +  //   adjust_pre_iter = (BOI - old_limit) % AW                               (11b)
    +  //
    +  // Case C: scale > 0 && stride < 0 (i.e. sign(scale) =  1)
    +  //   (BOI + old_limit - adjust_pre_iter) % AW = 0
    +  //   adjust_pre_iter = (BOI + old_limit) % AW                               (11c)
    +  //
    +  // Case D: scale < 0 && stride < 0 (i.e. sign(scale) = -1)
    +  //   (BOI - old_limit + adjust_pre_iter) % AW = 0
    +  //   adjust_pre_iter = (-BOI + old_limit) % AW                              (11d)
    +  //
    +  // We now generalize the equations (11*) by using:
    +  //
    +  //   OP:   (stride         > 0) ? SUB   : ADD
    +  //   XBOI: (stride * scale > 0) ? -BOI  : BOI
    +  //
    +  // which gives us the final pre-loop limit adjustment:
    +  //
    +  //   adjust_pre_iter = (XBOI OP old_limit) % AW                             (12)
    +  //
    +  // We can construct XBOI by additionally defining:
    +  //
    +  //   xboi = (stride * scale > 0) ? -boi              : boi                  (13)
    +  //
    +  // which gives us:
    +  //
    +  //   XBOI = (stride * scale > 0) ? -BOI              : BOI
    +  //        = (stride * scale > 0) ? -boi / abs(scale) : boi / abs(scale)
    +  //        = xboi / abs(scale)                                               (14)
    +  //
    +  // When we have computed adjust_pre_iter, we update the pre-loop limit
    +  // with (3a, b). However, we have to make sure that the adjust_pre_iter
    +  // additional pre-loop iterations do not lead the pre-loop to execute
    +  // iterations that would step over the original limit (orig_limit) of
    +  // the loop. Hence, we must constrain the updated limit as follows:
    +  //
    +  // constrained_limit = MIN(old_limit + adjust_pre_iter, orig_limit)
    +  //                   = MIN(new_limit,                   orig_limit)         (15a, stride > 0)
    +  // constrained_limit = MAX(old_limit - adjust_pre_iter, orig_limit)
    +  //                   = MAX(new_limit,                   orig_limit)         (15a, stride < 0)
    +
    +  // We chose an aw that is the maximal possible vector width for the type of
    +  // align_to_ref.
    +  const int aw       = vector_width_in_bytes(align_to_ref);
    +  const int stride   = iv_stride();
    +  const int scale    = align_to_ref_p.scale_in_bytes();
    +  const int offset   = align_to_ref_p.offset_in_bytes();
    +  Node* base         = align_to_ref_p.adr();
    +  Node* invar        = align_to_ref_p.invar();
    +
    +#ifdef ASSERT
    +  if (is_trace_align_vector()) {
    +    tty->print_cr("\nadjust_pre_loop_limit_to_align_main_loop_vectors:");
    +    tty->print("  align_to_ref:");
    +    align_to_ref->dump();
    +    tty->print_cr("  aw:       %d", aw);
    +    tty->print_cr("  stride:   %d", stride);
    +    tty->print_cr("  scale:    %d", scale);
    +    tty->print_cr("  offset:   %d", offset);
    +    tty->print("  base:");
    +    base->dump();
    +    if (invar == nullptr) {
    +      tty->print_cr("  invar:     null");
    +    } else {
    +      tty->print("  invar:");
    +      invar->dump();
    +    }
    +    tty->print("  old_limit: ");
    +    old_limit->dump();
    +    tty->print("  orig_limit: ");
    +    orig_limit->dump();
    +  }
    +#endif
    +
    +  if (stride == 0 || !is_power_of_2(abs(stride)) ||
    +      scale  == 0 || !is_power_of_2(abs(scale))  ||
    +      abs(scale) >= aw) {
    +#ifdef ASSERT
    +    if (is_trace_align_vector()) {
    +      tty->print_cr(" Alignment cannot be affected by changing pre-loop limit because");
    +      tty->print_cr(" stride or scale are not power of 2, or abs(scale) >= aw.");
    +    }
    +#endif
    +    // Cannot affect alignment, abort.
    +    return;
    +  }
    +
    +  assert(stride != 0 && is_power_of_2(abs(stride)) &&
    +         scale  != 0 && is_power_of_2(abs(scale))  &&
    +         abs(scale) < aw, "otherwise we cannot affect alignment with pre-loop");
    +
    +  const int AW = aw / abs(scale);
    +
    +#ifdef ASSERT
    +  if (is_trace_align_vector()) {
    +    tty->print_cr("  AW = aw(%d) / abs(scale(%d)) = %d", aw, scale, AW);
    +  }
    +#endif
    +
    +  // 1: Compute (13a, b):
    +  //    xboi = -boi = (-base - offset - invar)         (stride * scale > 0)
    +  //    xboi = +boi = (+base + offset + invar)         (stride * scale < 0)
    +  const bool is_sub = scale * stride > 0;
    +
    +  // 1.1: offset
    +  Node* xboi = _igvn.intcon(is_sub ? -offset : offset);
    +  TRACE_ALIGN_VECTOR_NODE(xboi);
    +
    +  // 1.2: invar (if it exists)
    +  if (invar != nullptr) {
         if (_igvn.type(invar)->isa_long()) {
           // Computations are done % (vector width/element size) so it's
           // safe to simply convert invar to an int and loose the upper 32
           // bit half.
           invar = new ConvL2INode(invar);
           _igvn.register_new_node_with_optimizer(invar);
    +      TRACE_ALIGN_VECTOR_NODE(invar);
    +   }
    +    if (is_sub) {
    +      xboi = new SubINode(xboi, invar);
    +    } else {
    +      xboi = new AddINode(xboi, invar);
         }
    -    Node* aref = new URShiftINode(invar, log2_elt);
    -    _igvn.register_new_node_with_optimizer(aref);
    -    _phase->set_ctrl(aref, pre_ctrl);
    -    e =  new AddINode(e, aref);
    -    _igvn.register_new_node_with_optimizer(e);
    -    _phase->set_ctrl(e, pre_ctrl);
    +    _igvn.register_new_node_with_optimizer(xboi);
    +    _phase->set_ctrl(xboi, pre_ctrl);
    +    TRACE_ALIGN_VECTOR_NODE(xboi);
       }
    -  if (vw > ObjectAlignmentInBytes || align_to_ref_p.base()->is_top()) {
    -    // incorporate base e +/- base && Mask >>> log2(elt)
    -    Node* xbase = new CastP2XNode(nullptr, align_to_ref_p.adr());
    +
    +  // 1.3: base (unless base is guaranteed aw aligned)
    +  if (aw > ObjectAlignmentInBytes || align_to_ref_p.base()->is_top()) {
    +    // The base is only aligned with ObjectAlignmentInBytes with arrays.
    +    // When the base() is top, we have no alignment guarantee at all.
    +    // Hence, we must now take the base into account for the calculation.
    +    Node* xbase = new CastP2XNode(nullptr, base);
         _igvn.register_new_node_with_optimizer(xbase);
    +    TRACE_ALIGN_VECTOR_NODE(xbase);
     #ifdef _LP64
         xbase  = new ConvL2INode(xbase);
         _igvn.register_new_node_with_optimizer(xbase);
    +    TRACE_ALIGN_VECTOR_NODE(xbase);
     #endif
    -    Node* mask = _igvn.intcon(vw-1);
    -    Node* masked_xbase  = new AndINode(xbase, mask);
    -    _igvn.register_new_node_with_optimizer(masked_xbase);
    -    Node* log2_elt = _igvn.intcon(exact_log2(elt_size));
    -    Node* bref     = new URShiftINode(masked_xbase, log2_elt);
    -    _igvn.register_new_node_with_optimizer(bref);
    -    _phase->set_ctrl(bref, pre_ctrl);
    -    e = new AddINode(e, bref);
    -    _igvn.register_new_node_with_optimizer(e);
    -    _phase->set_ctrl(e, pre_ctrl);
    -  }
    -
    -  // compute e +/- lim0
    -  if (scale < 0) {
    -    e = new SubINode(e, lim0);
    +    if (is_sub) {
    +      xboi = new SubINode(xboi, xbase);
    +    } else {
    +      xboi = new AddINode(xboi, xbase);
    +    }
    +    _igvn.register_new_node_with_optimizer(xboi);
    +    _phase->set_ctrl(xboi, pre_ctrl);
    +    TRACE_ALIGN_VECTOR_NODE(xboi);
    +  }
    +
    +  // 2: Compute (14):
    +  //    XBOI = xboi / abs(scale)
    +  //    The division is executed as shift
    +  Node* log2_abs_scale = _igvn.intcon(exact_log2(abs(scale)));
    +  Node* XBOI = new URShiftINode(xboi, log2_abs_scale);
    +  _igvn.register_new_node_with_optimizer(XBOI);
    +  _phase->set_ctrl(XBOI, pre_ctrl);
    +  TRACE_ALIGN_VECTOR_NODE(log2_abs_scale);
    +  TRACE_ALIGN_VECTOR_NODE(XBOI);
    +
    +  // 3: Compute (12):
    +  //    adjust_pre_iter = (XBOI OP old_limit) % AW
    +  //
    +  // 3.1: XBOI_OP_old_limit = XBOI OP old_limit
    +  Node* XBOI_OP_old_limit = nullptr;
    +  if (stride > 0) {
    +    XBOI_OP_old_limit = new SubINode(XBOI, old_limit);
       } else {
    -    e = new AddINode(e, lim0);
    -  }
    -  _igvn.register_new_node_with_optimizer(e);
    -  _phase->set_ctrl(e, pre_ctrl);
    -
    -  if (stride * scale > 0) {
    -    // compute V - (e +/- lim0)
    -    Node* va  = _igvn.intcon(v_align);
    -    e = new SubINode(va, e);
    -    _igvn.register_new_node_with_optimizer(e);
    -    _phase->set_ctrl(e, pre_ctrl);
    -  }
    -  // compute N = (exp) % V
    -  Node* va_msk = _igvn.intcon(v_align - 1);
    -  Node* N = new AndINode(e, va_msk);
    -  _igvn.register_new_node_with_optimizer(N);
    -  _phase->set_ctrl(N, pre_ctrl);
    -
    -  //   substitute back into (1), so that new limit
    -  //     lim = lim0 + N
    -  Node* lim;
    +    XBOI_OP_old_limit = new AddINode(XBOI, old_limit);
    +  }
    +  _igvn.register_new_node_with_optimizer(XBOI_OP_old_limit);
    +  _phase->set_ctrl(XBOI_OP_old_limit, pre_ctrl);
    +  TRACE_ALIGN_VECTOR_NODE(XBOI_OP_old_limit);
    +
    +  // 3.2: Compute:
    +  //    adjust_pre_iter = (XBOI OP old_limit) % AW
    +  //                    = XBOI_OP_old_limit % AW
    +  //                    = XBOI_OP_old_limit AND (AW - 1)
    +  //    Since AW is a power of 2, the modulo operation can be replaced with
    +  //    a bitmask operation.
    +  Node* mask_AW = _igvn.intcon(AW-1);
    +  Node* adjust_pre_iter = new AndINode(XBOI_OP_old_limit, mask_AW);
    +  _igvn.register_new_node_with_optimizer(adjust_pre_iter);
    +  _phase->set_ctrl(adjust_pre_iter, pre_ctrl);
    +  TRACE_ALIGN_VECTOR_NODE(mask_AW);
    +  TRACE_ALIGN_VECTOR_NODE(adjust_pre_iter);
    +
    +  // 4: Compute (3a, b):
    +  //    new_limit = old_limit + adjust_pre_iter     (stride > 0)
    +  //    new_limit = old_limit - adjust_pre_iter     (stride < 0)
    +  Node* new_limit = nullptr;
       if (stride < 0) {
    -    lim = new SubINode(lim0, N);
    +    new_limit = new SubINode(old_limit, adjust_pre_iter);
       } else {
    -    lim = new AddINode(lim0, N);
    -  }
    -  _igvn.register_new_node_with_optimizer(lim);
    -  _phase->set_ctrl(lim, pre_ctrl);
    -  Node* constrained =
    -    (stride > 0) ? (Node*) new MinINode(lim, orig_limit)
    -                 : (Node*) new MaxINode(lim, orig_limit);
    -  _igvn.register_new_node_with_optimizer(constrained);
    -  _phase->set_ctrl(constrained, pre_ctrl);
    -  _igvn.replace_input_of(pre_opaq, 1, constrained);
    +    new_limit = new AddINode(old_limit, adjust_pre_iter);
    +  }
    +  _igvn.register_new_node_with_optimizer(new_limit);
    +  _phase->set_ctrl(new_limit, pre_ctrl);
    +  TRACE_ALIGN_VECTOR_NODE(new_limit);
    +
    +  // 5: Compute (15a, b):
    +  //    Prevent pre-loop from going past the original limit of the loop.
    +  Node* constrained_limit =
    +    (stride > 0) ? (Node*) new MinINode(new_limit, orig_limit)
    +                 : (Node*) new MaxINode(new_limit, orig_limit);
    +  _igvn.register_new_node_with_optimizer(constrained_limit);
    +  _phase->set_ctrl(constrained_limit, pre_ctrl);
    +  TRACE_ALIGN_VECTOR_NODE(constrained_limit);
    +
    +  // 6: Hack the pre-loop limit
    +  _igvn.replace_input_of(pre_opaq, 1, constrained_limit);
     }
     
     //------------------------------init---------------------------
    diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp
    index 2319636c99a..db7101b26cb 100644
    --- a/src/hotspot/share/opto/superword.hpp
    +++ b/src/hotspot/share/opto/superword.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -247,7 +247,7 @@ class SuperWord : public ResourceObj {
       GrowableArray _mem_slice_tail;  // Memory slice tail nodes
       GrowableArray _node_info;  // Info needed per node
       CloneMap&            _clone_map;       // map of nodes created in cloning
    -  MemNode* _align_to_ref;                // Memory reference that pre-loop will align to
    +  MemNode const* _align_to_ref;          // Memory reference that pre-loop will align to
     
       GrowableArray _disjoint_ptrs; // runtime disambiguated pointer pairs
     
    @@ -281,6 +281,7 @@ class SuperWord : public ResourceObj {
       bool     is_trace_loop()         { return (_vector_loop_debug & 8) > 0; }
       bool     is_trace_adjacent()     { return (_vector_loop_debug & 16) > 0; }
       bool     is_trace_cmov()         { return (_vector_loop_debug & 32) > 0; }
    +  bool     is_trace_align_vector() { return (_vector_loop_debug & 128) > 0; }
     #endif
       bool     do_vector_loop()        { return _do_vector_loop; }
     
    @@ -315,17 +316,17 @@ class SuperWord : public ResourceObj {
       }
       int iv_stride() const            { return lp()->stride_con(); }
     
    -  int vector_width(Node* n) {
    +  int vector_width(const Node* n) const {
         BasicType bt = velt_basic_type(n);
         return MIN2(ABS(iv_stride()), Matcher::max_vector_size(bt));
       }
    -  int vector_width_in_bytes(Node* n) {
    +  int vector_width_in_bytes(const Node* n) const {
         BasicType bt = velt_basic_type(n);
         return vector_width(n)*type2aelembytes(bt);
       }
       int get_vw_bytes_special(MemNode* s);
    -  MemNode* align_to_ref()            { return _align_to_ref; }
    -  void  set_align_to_ref(MemNode* m) { _align_to_ref = m; }
    +  const MemNode* align_to_ref() const { return _align_to_ref; }
    +  void set_align_to_ref(const MemNode* m) { _align_to_ref = m; }
     
       const Node* ctrl(const Node* n) const { return _phase->has_ctrl(n) ? _phase->get_ctrl(n) : n; }
     
    @@ -360,8 +361,8 @@ class SuperWord : public ResourceObj {
       void set_depth(Node* n, int d)             { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_depth = d; }
     
       // vector element type
    -  const Type* velt_type(Node* n)             { return _node_info.adr_at(bb_idx(n))->_velt_type; }
    -  BasicType velt_basic_type(Node* n)         { return velt_type(n)->array_element_basic_type(); }
    +  const Type* velt_type(const Node* n) const { return _node_info.adr_at(bb_idx(n))->_velt_type; }
    +  BasicType velt_basic_type(const Node* n) const { return velt_type(n)->array_element_basic_type(); }
       void set_velt_type(Node* n, const Type* t) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_velt_type = t; }
       bool same_velt_type(Node* n1, Node* n2);
       bool same_memory_slice(MemNode* best_align_to_mem_ref, MemNode* mem_ref) const;
    @@ -441,21 +442,10 @@ class SuperWord : public ResourceObj {
       bool SLP_extract();
       // Find the adjacent memory references and create pack pairs for them.
       void find_adjacent_refs();
    -  // Tracing support
    -  #ifndef PRODUCT
    -  void find_adjacent_refs_trace_1(Node* best_align_to_mem_ref, int best_iv_adjustment);
    -  #endif
    -  // If strict memory alignment is required (vectors_should_be_aligned), then check if
    -  // mem_ref is aligned with best_align_to_mem_ref.
    -  bool mem_ref_has_no_alignment_violation(MemNode* mem_ref, int iv_adjustment, VPointer& align_to_ref_p,
    -                                          MemNode* best_align_to_mem_ref, int best_iv_adjustment,
    -                                          Node_List &align_to_refs);
       // Find a memory reference to align the loop induction variable to.
       MemNode* find_align_to_ref(Node_List &memops, int &idx);
       // Calculate loop's iv adjustment for this memory ops.
       int get_iv_adjustment(MemNode* mem);
    -  // Can the preloop align the reference to position zero in the vector?
    -  bool ref_is_alignable(VPointer& p);
       // Construct dependency graph.
       void dependence_graph();
       // Return a memory slice (node list) in predecessor order starting at "start"
    @@ -497,6 +487,12 @@ class SuperWord : public ResourceObj {
       int unpack_cost(int ct);
       // Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last
       void combine_packs();
    +  // Ensure all packs are aligned, if AlignVector is on.
    +  void filter_packs_for_alignment();
    +  // Find the set of alignment solutions for load/store pack.
    +  const AlignmentSolution* pack_alignment_solution(Node_List* pack);
    +  // Compress packset, such that it has no nullptr entries.
    +  void compress_packset();
       // Construct the map from nodes to packs.
       void construct_my_pack_map();
       // Remove packs that are not implemented or not profitable.
    @@ -544,9 +540,8 @@ class SuperWord : public ResourceObj {
       int memory_alignment(MemNode* s, int iv_adjust);
       // Smallest type containing range of values
       const Type* container_type(Node* n);
    -  // Adjust pre-loop limit so that in main loop, a load/store reference
    -  // to align_to_ref will be a position zero in the vector.
    -  void align_initial_loop_index(MemNode* align_to_ref);
    +  // Ensure that the main loop vectors are aligned by adjusting the pre loop limit.
    +  void adjust_pre_loop_limit_to_align_main_loop_vectors();
       // Is the use of d1 in u1 at the same operand position as d2 in u2?
       bool opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2);
       void init();
    diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp
    index f93f3ac069b..76ce36cf51c 100644
    --- a/src/hotspot/share/opto/type.cpp
    +++ b/src/hotspot/share/opto/type.cpp
    @@ -4860,7 +4860,7 @@ template   bool TypePtr::is_meet_subtype_of_helper_for_array
         return this_one->is_reference_type(this_elem)->is_meet_subtype_of_helper(this_one->is_reference_type(other_elem), this_xk, other_xk);
       }
       if (other_elem == nullptr && this_elem == nullptr) {
    -    return this_one->_klass->is_subtype_of(other->_klass);
    +    return this_one->klass()->is_subtype_of(other->klass());
       }
     
       return false;
    @@ -6380,7 +6380,7 @@ template  bool TypePtr::is_java_subtype_of_helper_for_instan
         return true;
       }
     
    -  return this_one->_klass->is_subtype_of(other->_klass) && this_one->_interfaces->contains(other->_interfaces);
    +  return this_one->klass()->is_subtype_of(other->klass()) && this_one->_interfaces->contains(other->_interfaces);
     }
     
     bool TypeInstKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const {
    @@ -6395,7 +6395,7 @@ template  bool TypePtr::is_same_java_type_as_helper_for_inst
       if (!this_one->is_instance_type(other)) {
         return false;
       }
    -  return this_one->_klass->equals(other->_klass) && this_one->_interfaces->eq(other->_interfaces);
    +  return this_one->klass()->equals(other->klass()) && this_one->_interfaces->eq(other->_interfaces);
     }
     
     bool TypeInstKlassPtr::is_same_java_type_as_helper(const TypeKlassPtr* other) const {
    @@ -6409,7 +6409,7 @@ template  bool TypePtr::maybe_java_subtype_of_helper_for_ins
       }
     
       if (this_one->is_array_type(other)) {
    -    return !this_exact && this_one->_klass->equals(ciEnv::current()->Object_klass())  && other->_interfaces->contains(this_one->_interfaces);
    +    return !this_exact && this_one->klass()->equals(ciEnv::current()->Object_klass())  && other->_interfaces->contains(this_one->_interfaces);
       }
     
       assert(this_one->is_instance_type(other), "unsupported");
    @@ -6418,12 +6418,12 @@ template  bool TypePtr::maybe_java_subtype_of_helper_for_ins
         return this_one->is_java_subtype_of(other);
       }
     
    -  if (!this_one->_klass->is_subtype_of(other->_klass) && !other->_klass->is_subtype_of(this_one->_klass)) {
    +  if (!this_one->klass()->is_subtype_of(other->klass()) && !other->klass()->is_subtype_of(this_one->klass())) {
         return false;
       }
     
       if (this_exact) {
    -    return this_one->_klass->is_subtype_of(other->_klass) && this_one->_interfaces->contains(other->_interfaces);
    +    return this_one->klass()->is_subtype_of(other->klass()) && this_one->_interfaces->contains(other->_interfaces);
       }
     
       return true;
    @@ -6543,7 +6543,7 @@ uint TypeAryKlassPtr::hash(void) const {
     
     //----------------------compute_klass------------------------------------------
     // Compute the defining klass for this class
    -ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const {
    +ciKlass* TypeAryPtr::compute_klass() const {
       // Compute _klass based on element type.
       ciKlass* k_ary = nullptr;
       const TypeInstPtr *tinst;
    @@ -6569,28 +6569,7 @@ ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const {
         // and object; Top occurs when doing join on Bottom.
         // Leave k_ary at null.
       } else {
    -    // Cannot compute array klass directly from basic type,
    -    // since subtypes of TypeInt all have basic type T_INT.
    -#ifdef ASSERT
    -    if (verify && el->isa_int()) {
    -      // Check simple cases when verifying klass.
    -      BasicType bt = T_ILLEGAL;
    -      if (el == TypeInt::BYTE) {
    -        bt = T_BYTE;
    -      } else if (el == TypeInt::SHORT) {
    -        bt = T_SHORT;
    -      } else if (el == TypeInt::CHAR) {
    -        bt = T_CHAR;
    -      } else if (el == TypeInt::INT) {
    -        bt = T_INT;
    -      } else {
    -        return _klass; // just return specified klass
    -      }
    -      return ciTypeArrayKlass::make(bt);
    -    }
    -#endif
    -    assert(!el->isa_int(),
    -           "integral arrays must be pre-equipped with a class");
    +    assert(!el->isa_int(), "integral arrays must be pre-equipped with a class");
         // Compute array klass directly from basic type
         k_ary = ciTypeArrayKlass::make(el->basic_type());
       }
    @@ -6915,7 +6894,7 @@ template  bool TypePtr::is_java_subtype_of_helper_for_array(
         return this_one->is_reference_type(this_elem)->is_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact);
       }
       if (this_elem == nullptr && other_elem == nullptr) {
    -    return this_one->_klass->is_subtype_of(other->_klass);
    +    return this_one->klass()->is_subtype_of(other->klass());
       }
       return false;
     }
    @@ -6947,8 +6926,7 @@ template  bool TypePtr::is_same_java_type_as_helper_for_arra
         return this_one->is_reference_type(this_elem)->is_same_java_type_as(this_one->is_reference_type(other_elem));
       }
       if (other_elem == nullptr && this_elem == nullptr) {
    -    assert(this_one->_klass != nullptr && other->_klass != nullptr, "");
    -    return this_one->_klass->equals(other->_klass);
    +    return this_one->klass()->equals(other->klass());
       }
       return false;
     }
    @@ -6968,7 +6946,7 @@ template  bool TypePtr::maybe_java_subtype_of_helper_for_arr
         return true;
       }
       if (this_one->is_instance_type(other)) {
    -    return other->_klass->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces);
    +    return other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces);
       }
       assert(this_one->is_array_type(other), "");
     
    @@ -6987,7 +6965,7 @@ template  bool TypePtr::maybe_java_subtype_of_helper_for_arr
         return this_one->is_reference_type(this_elem)->maybe_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact);
       }
       if (other_elem == nullptr && this_elem == nullptr) {
    -    return this_one->_klass->is_subtype_of(other->_klass);
    +    return this_one->klass()->is_subtype_of(other->klass());
       }
       return false;
     }
    diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp
    index 4e38e465806..0c6f46611ea 100644
    --- a/src/hotspot/share/opto/type.hpp
    +++ b/src/hotspot/share/opto/type.hpp
    @@ -1481,7 +1481,7 @@ class TypeAryPtr : public TypeOopPtr {
       Offset meet_field_offset(const Type::Offset offset) const;
       Offset dual_field_offset() const;
     
    -  ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const;
    +  ciKlass* compute_klass() const;
     
       // A pointer to delay allocation to Type::Initialize_shared()
     
    diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp
    index 2485069356f..95cda84fb24 100644
    --- a/src/hotspot/share/opto/vector.cpp
    +++ b/src/hotspot/share/opto/vector.cpp
    @@ -488,7 +488,7 @@ void PhaseVector::expand_vunbox_node(VectorUnboxNode* vec_unbox) {
         // For proper aliasing, attach concrete payload type.
         ciKlass* payload_klass = ciTypeArrayKlass::make(bt);
         const Type* payload_type = TypeAryPtr::make_from_klass(payload_klass)->cast_to_ptr_type(TypePtr::NotNull);
    -    vec_field_ld = gvn.transform(new CastPPNode(vec_field_ld, payload_type));
    +    vec_field_ld = gvn.transform(new CastPPNode(nullptr, vec_field_ld, payload_type));
     
         Node* adr = kit.array_element_address(vec_field_ld, gvn.intcon(0), bt);
         const TypePtr* adr_type = adr->bottom_type()->is_ptr();
    diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp
    index 7158f400929..4794140ab0e 100644
    --- a/src/hotspot/share/opto/vectorization.cpp
    +++ b/src/hotspot/share/opto/vectorization.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2023, Arm Limited. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
    @@ -35,7 +35,8 @@
     int VPointer::Tracer::_depth = 0;
     #endif
     
    -VPointer::VPointer(MemNode* mem, PhaseIdealLoop* phase, IdealLoopTree* lpt,
    +VPointer::VPointer(const MemNode* mem,
    +                   PhaseIdealLoop* phase, IdealLoopTree* lpt,
                        Node_Stack* nstack, bool analyze_only) :
       _mem(mem), _phase(phase), _lpt(lpt),
       _iv(lpt->_head->as_CountedLoop()->phi()->as_Phi()),
    @@ -119,6 +120,22 @@ VPointer::VPointer(VPointer* p) :
     #endif
     {}
     
    +// Biggest detectable factor of the invariant.
    +int VPointer::invar_factor() const {
    +  Node* n = invar();
    +  if (n == nullptr) {
    +    return 0;
    +  }
    +  int opc = n->Opcode();
    +  if (opc == Op_LShiftI && n->in(2)->is_Con()) {
    +    return 1 << n->in(2)->get_int();
    +  } else if (opc == Op_LShiftL && n->in(2)->is_Con()) {
    +    return 1 << n->in(2)->get_int();
    +  }
    +  // All our best-effort has failed.
    +  return 1;
    +}
    +
     bool VPointer::is_loop_member(Node* n) const {
       Node* n_c = phase()->get_ctrl(n);
       return lpt()->is_member(phase()->get_loop(n_c));
    @@ -417,7 +434,7 @@ void VPointer::Tracer::print_depth() const {
       }
     }
     
    -void VPointer::Tracer::ctor_1(Node* mem) {
    +void VPointer::Tracer::ctor_1(const Node* mem) {
       if (_is_trace_alignment) {
         print_depth(); tty->print(" %d VPointer::VPointer: start alignment analysis", mem->_idx); mem->dump();
       }
    @@ -459,7 +476,7 @@ void VPointer::Tracer::ctor_5(Node* adr, Node* base, int i) {
       }
     }
     
    -void VPointer::Tracer::ctor_6(Node* mem) {
    +void VPointer::Tracer::ctor_6(const Node* mem) {
       if (_is_trace_alignment) {
         //restore_depth();
         print_depth(); tty->print_cr(" %d (adr) VPointer::VPointer: stop analysis", mem->_idx);
    @@ -685,5 +702,655 @@ void VPointer::Tracer::offset_plus_k_11(Node* n) {
         print_depth(); tty->print_cr(" %d VPointer::offset_plus_k: FAILED", n->_idx);
       }
     }
    +#endif
    +
    +
    +AlignmentSolution* AlignmentSolver::solve() const {
    +  DEBUG_ONLY( trace_start_solve(); )
    +
    +  // Out of simplicity: non power-of-2 stride not supported.
    +  if (!is_power_of_2(abs(_pre_stride))) {
    +    return new EmptyAlignmentSolution("non power-of-2 stride not supported");
    +  }
    +  assert(is_power_of_2(abs(_main_stride)), "main_stride is power of 2");
    +  assert(_aw > 0 && is_power_of_2(_aw), "aw must be power of 2");
    +
    +  // Out of simplicity: non power-of-2 scale not supported.
    +  if (abs(_scale) == 0 || !is_power_of_2(abs(_scale))) {
    +    return new EmptyAlignmentSolution("non power-of-2 scale not supported");
    +  }
    +
    +  // We analyze the address of mem_ref. The idea is to disassemble it into a linear
    +  // expression, where we can use the constant factors as the basis for ensuring the
    +  // alignment of vector memory accesses.
    +  //
    +  // The Simple form of the address is disassembled by VPointer into:
    +  //
    +  //   adr = base + offset + invar + scale * iv
    +  //
    +  // Where the iv can be written as:
    +  //
    +  //   iv = init + pre_stride * pre_iter + main_stride * main_iter
    +  //
    +  // init:        value before pre-loop
    +  // pre_stride:  increment per pre-loop iteration
    +  // pre_iter:    number of pre-loop iterations (adjustable via pre-loop limit)
    +  // main_stride: increment per main-loop iteration (= pre_stride * unroll_factor)
    +  // main_iter:   number of main-loop iterations (main_iter >= 0)
    +  //
    +  // In the following, we restate the Simple form of the address expression, by first
    +  // expanding the iv variable. In a second step, we reshape the expression again, and
    +  // state it as a linear expression, consisting of 6 terms.
    +  //
    +  //          Simple form           Expansion of iv variable                  Reshaped with constants   Comments for terms
    +  //          -----------           ------------------------                  -----------------------   ------------------
    +  //   adr =  base               =  base                                   =  base                      (base % aw = 0)
    +  //        + offset              + offset                                  + C_const                   (sum of constant terms)
    +  //        + invar               + invar_factor * var_invar                + C_invar * var_invar       (term for invariant)
    +  //                          /   + scale * init                            + C_init  * var_init        (term for variable init)
    +  //        + scale * iv   -> |   + scale * pre_stride * pre_iter           + C_pre   * pre_iter        (adjustable pre-loop term)
    +  //                          \   + scale * main_stride * main_iter         + C_main  * main_iter       (main-loop term)
    +  //
    +  // We describe the 6 terms:
    +  //   1) The "base" of the address is the address of a Java object (e.g. array),
    +  //      and as such ObjectAlignmentInBytes (a power of 2) aligned. We have
    +  //      defined aw = MIN(vector_width, ObjectAlignmentInBytes), which is also
    +  //      a power of 2. And hence we know that "base" is thus also aw-aligned:
    +  //
    +  //        base % ObjectAlignmentInBytes = 0     ==>    base % aw = 0
    +  //
    +  //   2) The "C_const" term is the sum of all constant terms. This is "offset",
    +  //      plus "scale * init" if it is constant.
    +  //   3) The "C_invar * var_invar" is the factorization of "invar" into a constant
    +  //      and variable term. If there is no invariant, then "C_invar" is zero.
    +  //
    +  //        invar = C_invar * var_invar                                             (FAC_INVAR)
    +  //
    +  //   4) The "C_init * var_init" is the factorization of "scale * init" into a
    +  //      constant and a variable term. If "init" is constant, then "C_init" is
    +  //      zero, and "C_const" accounts for "init" instead.
    +  //
    +  //        scale * init = C_init * var_init + scale * C_const_init                 (FAC_INIT)
    +  //        C_init       = (init is constant) ? 0    : scale
    +  //        C_const_init = (init is constant) ? init : 0
    +  //
    +  //   5) The "C_pre * pre_iter" term represents how much the iv is incremented
    +  //      during the "pre_iter" pre-loop iterations. This term can be adjusted
    +  //      by changing the pre-loop limit, which defines how many pre-loop iterations
    +  //      are executed. This allows us to adjust the alignment of the main-loop
    +  //      memory reference.
    +  //   6) The "C_main * main_iter" term represents how much the iv is increased
    +  //      during "main_iter" main-loop iterations.
    +
    +  // Attribute init (i.e. _init_node) either to C_const or to C_init term.
    +  const int C_const_init = _init_node->is_ConI() ? _init_node->as_ConI()->get_int() : 0;
    +  const int C_const =      _offset + C_const_init * _scale;
    +
    +  // Set C_invar depending on if invar is present
    +  const int C_invar = (_invar == nullptr) ? 0 : abs(_invar_factor);
    +
    +  const int C_init = _init_node->is_ConI() ? 0 : _scale;
    +  const int C_pre =  _scale * _pre_stride;
    +  const int C_main = _scale * _main_stride;
    +
    +  DEBUG_ONLY( trace_reshaped_form(C_const, C_const_init, C_invar, C_init, C_pre, C_main); )
    +
    +  // We must find a pre_iter, such that adr is aw aligned: adr % aw = 0. Note, that we are defining the
    +  // modulo operator "%" such that the remainder is always positive, see AlignmentSolution::mod(i, q).
    +  //
    +  // Since "base % aw = 0", we only need to ensure alignment of the other 5 terms:
    +  //
    +  //   (C_const + C_invar * var_invar + C_init * var_init + C_pre * pre_iter + C_main * main_iter) % aw = 0      (1)
    +  //
    +  // Alignment must be maintained over all main-loop iterations, i.e. for any main_iter >= 0, we require:
    +  //
    +  //   C_main % aw = 0                                                                                           (2)
    +  //
    +  const int C_main_mod_aw = AlignmentSolution::mod(C_main, _aw);
    +
    +  DEBUG_ONLY( trace_main_iteration_alignment(C_const, C_invar, C_init, C_pre, C_main, C_main_mod_aw); )
    +
    +  if (C_main_mod_aw != 0) {
    +    return new EmptyAlignmentSolution("EQ(2) not satisfied (cannot align across main-loop iterations)");
    +  }
    +
    +  // In what follows, we need to show that the C_const, init and invar terms can be aligned by
    +  // adjusting the pre-loop iteration count (pre_iter), which is controlled by the pre-loop
    +  // limit.
    +  //
    +  //     (C_const + C_invar * var_invar + C_init * var_init + C_pre * pre_iter) % aw = 0                         (3)
    +  //
    +  // We strengthen the constraints by splitting the equation into 3 equations, where we
    +  // want to find integer solutions for pre_iter_C_const, pre_iter_C_invar, and
    +  // pre_iter_C_init, which means that the C_const, init and invar terms can be aligned
    +  // independently:
    +  //
    +  //   (C_const             + C_pre * pre_iter_C_const) % aw = 0                 (4a)
    +  //   (C_invar * var_invar + C_pre * pre_iter_C_invar) % aw = 0                 (4b)
    +  //   (C_init  * var_init  + C_pre * pre_iter_C_init ) % aw = 0                 (4c)
    +  //
    +  // We now prove that (4a, b, c) are sufficient as well as necessary to guarantee (3)
    +  // for any runtime value of var_invar and var_init (i.e. for any invar and init).
    +  // This tells us that the "strengthening" does not restrict the algorithm more than
    +  // necessary.
    +  //
    +  // Sufficient (i.e (4a, b, c) imply (3)):
    +  //
    +  //   pre_iter = pre_iter_C_const + pre_iter_C_invar + pre_iter_C_init
    +  //
    +  // Adding up (4a, b, c):
    +  //
    +  //   0 = (  C_const             + C_pre * pre_iter_C_const
    +  //        + C_invar * var_invar + C_pre * pre_iter_C_invar
    +  //        + C_init  * var_init  + C_pre * pre_iter_C_init  ) % aw
    +  //
    +  //     = (  C_const + C_invar * var_invar + C_init * var_init
    +  //        + C_pre * (pre_iter_C_const + pre_iter_C_invar + pre_iter_C_init)) % aw
    +  //
    +  //     = (  C_const + C_invar * var_invar + C_init * var_init
    +  //        + C_pre * pre_iter) % aw
    +  //
    +  // Necessary (i.e. (3) implies (4a, b, c)):
    +  //  (4a): Set var_invar = var_init = 0 at runtime. Applying this to (3), we get:
    +  //
    +  //        0 =
    +  //          = (C_const + C_invar * var_invar + C_init * var_init + C_pre * pre_iter) % aw
    +  //          = (C_const + C_invar * 0         + C_init * 0        + C_pre * pre_iter) % aw
    +  //          = (C_const                                           + C_pre * pre_iter) % aw
    +  //
    +  //        This is of the same form as (4a), and we have a solution:
    +  //        pre_iter_C_const = pre_iter
    +  //
    +  //  (4b): Set var_init = 0, and assume (4a), which we just proved is implied by (3).
    +  //        Subtract (4a) from (3):
    +  //
    +  //        0 =
    +  //          =  (C_const + C_invar * var_invar + C_init * var_init + C_pre * pre_iter) % aw
    +  //           - (C_const + C_pre * pre_iter_C_const) % aw
    +  //          =  (C_invar * var_invar + C_init * var_init + C_pre * pre_iter - C_pre * pre_iter_C_const) % aw
    +  //          =  (C_invar * var_invar + C_init * 0        + C_pre * (pre_iter - pre_iter_C_const)) % aw
    +  //          =  (C_invar * var_invar +                   + C_pre * (pre_iter - pre_iter_C_const)) % aw
    +  //
    +  //        This is of the same form as (4b), and we have a solution:
    +  //        pre_iter_C_invar = pre_iter - pre_iter_C_const
    +  //
    +  //  (4c): Set var_invar = 0, and assume (4a), which we just proved is implied by (3).
    +  //        Subtract (4a) from (3):
    +  //
    +  //        0 =
    +  //          =  (C_const + C_invar * var_invar + C_init * var_init + C_pre * pre_iter) % aw
    +  //           - (C_const + C_pre * pre_iter_C_const) % aw
    +  //          =  (C_invar * var_invar + C_init * var_init + C_pre * pre_iter - C_pre * pre_iter_C_const) % aw
    +  //          =  (C_invar * 0         + C_init * var_init + C_pre * (pre_iter - pre_iter_C_const)) % aw
    +  //          =  (                    + C_init * var_init + C_pre * (pre_iter - pre_iter_C_const)) % aw
    +  //
    +  //        This is of the same form as (4c), and we have a solution:
    +  //        pre_iter_C_invar = pre_iter - pre_iter_C_const
    +  //
    +  // The solutions of Equations (4a, b, c) for pre_iter_C_const, pre_iter_C_invar, and pre_iter_C_init
    +  // respectively, can have one of these states:
    +  //
    +  //   trivial:     The solution can be any integer.
    +  //   constrained: There is a (periodic) solution, but it is not trivial.
    +  //   empty:       Statically we cannot guarantee a solution for all var_invar and var_init.
    +  //
    +  // We look at (4a):
    +  //
    +  //   abs(C_pre) >= aw
    +  //   -> Since abs(C_pre) is a power of two, we have C_pre % aw = 0. Therefore:
    +  //
    +  //        For any pre_iter_C_const: (C_pre * pre_iter_C_const) % aw = 0
    +  //
    +  //        (C_const + C_pre * pre_iter_C_const) % aw = 0
    +  //         C_const                             % aw = 0
    +  //
    +  //      Hence, we can only satisfy (4a) if C_Const is aw aligned:
    +  //
    +  //      C_const % aw == 0:
    +  //      -> (4a) has a trivial solution since we can choose any value for pre_iter_C_const.
    +  //
    +  //      C_const % aw != 0:
    +  //      -> (4a) has an empty solution since no pre_iter_C_const can achieve aw alignment.
    +  //
    +  //   abs(C_pre) < aw:
    +  //   -> Since both abs(C_pre) and aw are powers of two, we know:
    +  //
    +  //        There exists integer x > 1: aw = abs(C_pre) * x
    +  //
    +  //      C_const % abs(C_pre) == 0:
    +  //      -> There exists integer z: C_const = C_pre * z
    +  //
    +  //          (C_const   + C_pre * pre_iter_C_const) % aw               = 0
    +  //          ==>
    +  //          (C_pre * z + C_pre * pre_iter_C_const) % aw               = 0
    +  //          ==>
    +  //          (C_pre * z + C_pre * pre_iter_C_const) % (abs(C_pre) * x) = 0
    +  //          ==>
    +  //          (        z +         pre_iter_C_const) %               x  = 0
    +  //          ==>
    +  //          for any m: pre_iter_C_const = m * x - z
    +  //
    +  //        Hence, pre_iter_C_const has a non-trivial (because x > 1) periodic (periodicity x)
    +  //        solution, i.e. it has a constrained solution.
    +  //
    +  //      C_const % abs(C_pre) != 0:
    +  //        There exists integer x > 1: aw = abs(C_pre) * x
    +  //
    +  //           C_const                             %  abs(C_pre)      != 0
    +  //          ==>
    +  //          (C_const + C_pre * pre_iter_C_const) %  abs(C_pre)      != 0
    +  //          ==>
    +  //          (C_const + C_pre * pre_iter_C_const) % (abs(C_pre) * x) != 0
    +  //          ==>
    +  //          (C_const + C_pre * pre_iter_C_const) % aw               != 0
    +  //
    +  //        This is in contradiction with (4a), and therefore there cannot be any solution,
    +  //        i.e. we have an empty solution.
    +  //
    +  // In summary, for (4a):
    +  //
    +  //   abs(C_pre) >= aw  AND  C_const % aw == 0          -> trivial
    +  //   abs(C_pre) >= aw  AND  C_const % aw != 0          -> empty
    +  //   abs(C_pre) <  aw  AND  C_const % abs(C_pre) == 0  -> constrained
    +  //   abs(C_pre) <  aw  AND  C_const % abs(C_pre) != 0  -> empty
    +  //
    +  // With analogue argumentation for (4b):
    +  //
    +  //   abs(C_pre) >= aw  AND  C_invar % aw == 0           -> trivial
    +  //   abs(C_pre) >= aw  AND  C_invar % aw != 0           -> empty
    +  //   abs(C_pre) <  aw  AND  C_invar % abs(C_pre) == 0   -> constrained
    +  //   abs(C_pre) <  aw  AND  C_invar % abs(C_pre) != 0   -> empty
    +  //
    +  // With analogue argumentation for (4c):
    +  //
    +  //   abs(C_pre) >= aw  AND  C_init  % aw == 0           -> trivial
    +  //   abs(C_pre) >= aw  AND  C_init  % aw != 0           -> empty
    +  //   abs(C_pre) <  aw  AND  C_init  % abs(C_pre) == 0   -> constrained
    +  //   abs(C_pre) <  aw  AND  C_init  % abs(C_pre) != 0   -> empty
    +  //
    +  // Out of these states follows the state for the solution of pre_iter:
    +  //
    +  //   Trivial:     If (4a, b, c) are all trivial.
    +  //   Empty:       If any of (4a, b, c) is empty, because then we cannot guarantee a solution
    +  //                for pre_iter, for all possible invar and init values.
    +  //   Constrained: Else. Incidentally, (4a, b, c) are all constrained themselves, as we argue below.
    +
    +  const EQ4 eq4(C_const, C_invar, C_init, C_pre, _aw);
    +  const EQ4::State eq4a_state = eq4.eq4a_state();
    +  const EQ4::State eq4b_state = eq4.eq4b_state();
    +  const EQ4::State eq4c_state = eq4.eq4c_state();
    +
    +#ifdef ASSERT
    +  if (is_trace()) {
    +    eq4.trace();
    +  }
    +#endif
    +
    +  // If (4a, b, c) are all trivial, then also the solution for pre_iter is trivial:
    +  if (eq4a_state == EQ4::State::TRIVIAL &&
    +      eq4b_state == EQ4::State::TRIVIAL &&
    +      eq4c_state == EQ4::State::TRIVIAL) {
    +    return new TrivialAlignmentSolution();
    +  }
    +
    +  // If any of (4a, b, c) is empty, then we also cannot guarantee a solution for pre_iter, for
    +  // any init and invar, hence the solution for pre_iter is empty:
    +  if (eq4a_state == EQ4::State::EMPTY ||
    +      eq4b_state == EQ4::State::EMPTY ||
    +      eq4c_state == EQ4::State::EMPTY) {
    +    return new EmptyAlignmentSolution("EQ(4a, b, c) not all non-empty: cannot align const, invar and init terms individually");
    +  }
    +
    +  // If abs(C_pre) >= aw, then the solutions to (4a, b, c) are all either trivial or empty, and
    +  // hence we would have found the solution to pre_iter above as either trivial or empty. Thus
    +  // we now know that:
    +  //
    +  //   abs(C_pre) < aw
    +  //
    +  assert(abs(C_pre) < _aw, "implied by constrained case");
    +
    +  // And since abs(C_pre) < aw, the solutions of (4a, b, c) can now only be constrained or empty.
    +  // But since we already handled the empty case, the solutions are now all constrained.
    +  assert(eq4a_state == EQ4::State::CONSTRAINED &&
    +         eq4a_state == EQ4::State::CONSTRAINED &&
    +         eq4a_state == EQ4::State::CONSTRAINED, "all must be constrained now");
    +
    +  // And since they are all constrained, we must have:
    +  //
    +  //   C_const % abs(C_pre) = 0                                                  (5a)
    +  //   C_invar % abs(C_pre) = 0                                                  (5b)
    +  //   C_init  % abs(C_pre) = 0                                                  (5c)
    +  //
    +  assert(AlignmentSolution::mod(C_const, abs(C_pre)) == 0, "EQ(5a): C_const must be alignable");
    +  assert(AlignmentSolution::mod(C_invar, abs(C_pre)) == 0, "EQ(5b): C_invar must be alignable");
    +  assert(AlignmentSolution::mod(C_init,  abs(C_pre)) == 0, "EQ(5c): C_init  must be alignable");
    +
    +  // With (5a, b, c), we know that there are integers X, Y, Z:
    +  //
    +  //   C_const = X * abs(C_pre)   ==>   X = C_const / abs(C_pre)                 (6a)
    +  //   C_invar = Y * abs(C_pre)   ==>   Y = C_invar / abs(C_pre)                 (6b)
    +  //   C_init  = Z * abs(C_pre)   ==>   Z = C_init  / abs(C_pre)                 (6c)
    +  //
    +  // Further, we define:
    +  //
    +  //   sign(C_pre) = C_pre / abs(C_pre) = (C_pre > 0) ? 1 : -1,                  (7)
    +  //
    +  // We know that abs(C_pre) as well as aw are powers of 2, and since (5) we can define integer q:
    +  //
    +  //   q = aw / abs(C_pre)                                                       (8)
    +  //
    +  const int q = _aw / abs(C_pre);
    +
    +  assert(q >= 2, "implied by constrained solution");
    +
    +  // We now know that all terms in (4a, b, c) are divisible by abs(C_pre):
    +  //
    +  //   (C_const                    / abs(C_pre) + C_pre * pre_iter_C_const /  abs(C_pre)) % (aw / abs(C_pre)) =
    +  //   (X * abs(C_pre)             / abs(C_pre) + C_pre * pre_iter_C_const /  abs(C_pre)) % (aw / abs(C_pre)) =
    +  //   (X                                       +         pre_iter_C_const * sign(C_pre)) % q                 = 0  (9a)
    +  //
    +  //   -> pre_iter_C_const * sign(C_pre) = mx1 * q -               X
    +  //   -> pre_iter_C_const               = mx2 * q - sign(C_pre) * X                                               (10a)
    +  //      (for any integers mx1, mx2)
    +  //
    +  //   (C_invar        * var_invar / abs(C_pre) + C_pre * pre_iter_C_invar /  abs(C_pre)) % (aw / abs(C_pre)) =
    +  //   (Y * abs(C_pre) * var_invar / abs(C_pre) + C_pre * pre_iter_C_invar /  abs(C_pre)) % (aw / abs(C_pre)) =
    +  //   (Y              * var_invar              +         pre_iter_C_invar * sign(C_pre)) % q                 = 0  (9b)
    +  //
    +  //   -> pre_iter_C_invar * sign(C_pre) = my1 * q -               Y * var_invar
    +  //   -> pre_iter_C_invar               = my2 * q - sign(C_pre) * Y * var_invar                                   (10b)
    +  //      (for any integers my1, my2)
    +  //
    +  //   (C_init          * var_init  / abs(C_pre) + C_pre * pre_iter_C_init /  abs(C_pre)) % (aw / abs(C_pre)) =
    +  //   (Z * abs(C_pre)  * var_init  / abs(C_pre) + C_pre * pre_iter_C_init /  abs(C_pre)) % (aw / abs(C_pre)) =
    +  //   (Z * var_init                             +         pre_iter_C_init * sign(C_pre)) % q                 = 0  (9c)
    +  //
    +  //   -> pre_iter_C_init  * sign(C_pre) = mz1 * q -               Z * var_init
    +  //   -> pre_iter_C_init                = mz2 * q - sign(C_pre) * Z * var_init                                    (10c)
    +  //      (for any integers mz1, mz2)
    +  //
    +  //
    +  // Having solved the equations using the division, we can re-substitute X, Y, and Z, and apply (FAC_INVAR) as
    +  // well as (FAC_INIT). We use the fact that sign(x) == 1 / sign(x) and sign(x) * abs(x) == x:
    +  //
    +  //   pre_iter_C_const = mx2 * q - sign(C_pre) * X
    +  //                    = mx2 * q - sign(C_pre) * C_const             / abs(C_pre)
    +  //                    = mx2 * q - C_const / C_pre
    +  //                    = mx2 * q - C_const / (scale * pre_stride)                                  (11a)
    +  //
    +  // If there is an invariant:
    +  //
    +  //   pre_iter_C_invar = my2 * q - sign(C_pre) * Y       * var_invar
    +  //                    = my2 * q - sign(C_pre) * C_invar * var_invar / abs(C_pre)
    +  //                    = my2 * q - sign(C_pre) * invar               / abs(C_pre)
    +  //                    = my2 * q - invar / C_pre
    +  //                    = my2 * q - invar / (scale * pre_stride)                                    (11b, with invar)
    +  //
    +  // If there is no invariant (i.e. C_invar = 0 ==> Y = 0):
    +  //
    +  //   pre_iter_C_invar = my2 * q                                                                   (11b, no invar)
    +  //
    +  // If init is variable (i.e. C_init = scale, init = var_init):
    +  //
    +  //   pre_iter_C_init  = mz2 * q - sign(C_pre) * Z       * var_init
    +  //                    = mz2 * q - sign(C_pre) * C_init  * var_init  / abs(C_pre)
    +  //                    = mz2 * q - sign(C_pre) * scale   * init      / abs(C_pre)
    +  //                    = mz2 * q - scale * init / C_pre
    +  //                    = mz2 * q - scale * init / (scale * pre_stride)
    +  //                    = mz2 * q - init / pre_stride                                               (11c, variable init)
    +  //
    +  // If init is constant (i.e. C_init = 0 ==> Z = 0):
    +  //
    +  //   pre_iter_C_init  = mz2 * q                                                                   (11c, constant init)
    +  //
    +  // Note, that the solutions found by (11a, b, c) are all periodic with periodicity q. We combine them,
    +  // with m = mx2 + my2 + mz2:
    +  //
    +  //   pre_iter =   pre_iter_C_const + pre_iter_C_invar + pre_iter_C_init
    +  //            =   mx2 * q  - C_const / (scale * pre_stride)
    +  //              + my2 * q [- invar / (scale * pre_stride) ]
    +  //              + mz2 * q [- init / pre_stride            ]
    +  //
    +  //            =   m * q                                 (periodic part)
    +  //              - C_const / (scale * pre_stride)        (align constant term)
    +  //             [- invar / (scale * pre_stride)   ]      (align invariant term, if present)
    +  //             [- init / pre_stride              ]      (align variable init term, if present)    (12)
    +  //
    +  // We can further simplify this solution by introducing integer 0 <= r < q:
    +  //
    +  //   r = (-C_const / (scale * pre_stride)) % q                                                    (13)
    +  //
    +  const int r = AlignmentSolution::mod(-C_const / (_scale * _pre_stride), q);
    +  //
    +  //   pre_iter = m * q + r
    +  //                   [- invar / (scale * pre_stride)  ]
    +  //                   [- init / pre_stride             ]                                           (14)
    +  //
    +  // We thus get a solution that can be stated in terms of:
    +  //
    +  //   q (periodicity), r (constant alignment), invar, scale, pre_stride, init
    +  //
    +  // However, pre_stride and init are shared by all mem_ref in the loop, hence we do not need to provide
    +  // them in the solution description.
    +
    +  DEBUG_ONLY( trace_constrained_solution(C_const, C_invar, C_init, C_pre, q, r); )
    +
    +  return new ConstrainedAlignmentSolution(_mem_ref, q, r, _invar, _scale);
    +
    +  // APPENDIX:
    +  // We can now verify the success of the solution given by (12):
    +  //
    +  //   adr % aw =
    +  //
    +  //   -> Simple form
    +  //   (base + offset + invar + scale * iv) % aw =
    +  //
    +  //   -> Expand iv
    +  //   (base + offset + invar + scale * (init + pre_stride * pre_iter + main_stride * main_iter)) % aw =
    +  //
    +  //   -> Reshape
    +  //   (base + offset + invar
    +  //         + scale * init
    +  //         + scale * pre_stride * pre_iter
    +  //         + scale * main_stride * main_iter)) % aw =
    +  //
    +  //   -> base aligned: base % aw = 0
    +  //   -> main-loop iterations aligned (2): C_main % aw = (scale * main_stride) % aw = 0
    +  //   (offset + invar + scale * init + scale * pre_stride * pre_iter) % aw =
    +  //
    +  //   -> apply (12)
    +  //   (offset + invar + scale * init
    +  //           + scale * pre_stride * (m * q - C_const / (scale * pre_stride)
    +  //                                        [- invar / (scale * pre_stride) ]
    +  //                                        [- init / pre_stride            ]
    +  //                                  )
    +  //   ) % aw =
    +  //
    +  //   -> expand C_const = offset [+ init * scale]  (if init const)
    +  //   (offset + invar + scale * init
    +  //           + scale * pre_stride * (m * q - offset / (scale * pre_stride)
    +  //                                        [- init / pre_stride            ]             (if init constant)
    +  //                                        [- invar / (scale * pre_stride) ]             (if invar present)
    +  //                                        [- init / pre_stride            ]             (if init variable)
    +  //                                  )
    +  //   ) % aw =
    +  //
    +  //   -> assuming invar = 0 if it is not present
    +  //   -> merge the two init terms (variable or constant)
    +  //   -> apply (8): q = aw / (abs(C_pre)) = aw / abs(scale * pre_stride)
    +  //   -> and hence: (scale * pre_stride * q) % aw = 0
    +  //   -> all terms are canceled out
    +  //   (offset + invar + scale * init
    +  //           + scale * pre_stride * m * q                             -> aw aligned
    +  //           - scale * pre_stride * offset / (scale * pre_stride)     -> = offset
    +  //           - scale * pre_stride * init / pre_stride                 -> = scale * init
    +  //           - scale * pre_stride * invar / (scale * pre_stride)      -> = invar
    +  //   ) % aw = 0
    +  //
    +  // The solution given by (12) does indeed guarantee alignment.
    +}
     
    +#ifdef ASSERT
    +void print_con_or_idx(const Node* n) {
    +  if (n == nullptr) {
    +    tty->print("(0)");
    +  } else if (n->is_ConI()) {
    +    jint val = n->as_ConI()->get_int();
    +    tty->print("(%d)", val);
    +  } else {
    +    tty->print("[%d]", n->_idx);
    +  }
    +}
    +
    +void AlignmentSolver::trace_start_solve() const {
    +  if (is_trace()) {
    +    tty->print(" vector mem_ref:");
    +    _mem_ref->dump();
    +    tty->print_cr("  vector_width = vector_length(%d) * element_size(%d) = %d",
    +                  _vector_length, _element_size, _vector_width);
    +    tty->print_cr("  aw = alignment_width = min(vector_width(%d), ObjectAlignmentInBytes(%d)) = %d",
    +                  _vector_width, ObjectAlignmentInBytes, _aw);
    +
    +    if (!_init_node->is_ConI()) {
    +      tty->print("  init:");
    +      _init_node->dump();
    +    }
    +
    +    if (_invar != nullptr) {
    +      tty->print("  invar:");
    +      _invar->dump();
    +    }
    +
    +    tty->print_cr("  invar_factor = %d", _invar_factor);
    +
    +    // iv = init + pre_iter * pre_stride + main_iter * main_stride
    +    tty->print("  iv = init");
    +    print_con_or_idx(_init_node);
    +    tty->print_cr(" + pre_iter * pre_stride(%d) + main_iter * main_stride(%d)",
    +                  _pre_stride, _main_stride);
    +
    +    // adr = base + offset + invar + scale * iv
    +    tty->print("  adr = base");
    +    print_con_or_idx(_base);
    +    tty->print(" + offset(%d) + invar", _offset);
    +    print_con_or_idx(_invar);
    +    tty->print_cr(" + scale(%d) * iv", _scale);
    +  }
    +}
    +
    +void AlignmentSolver::trace_reshaped_form(const int C_const,
    +                                          const int C_const_init,
    +                                          const int C_invar,
    +                                          const int C_init,
    +                                          const int C_pre,
    +                                          const int C_main) const
    +{
    +  if (is_trace()) {
    +    tty->print("      = base[%d] + ", _base->_idx);
    +    tty->print_cr("C_const(%d) + C_invar(%d) * var_invar + C_init(%d) * var_init + C_pre(%d) * pre_iter + C_main(%d) * main_iter",
    +                  C_const, C_invar, C_init,  C_pre, C_main);
    +    if (_init_node->is_ConI()) {
    +      tty->print_cr("  init is constant:");
    +      tty->print_cr("    C_const_init = %d", C_const_init);
    +      tty->print_cr("    C_init = %d", C_init);
    +    } else {
    +      tty->print_cr("  init is variable:");
    +      tty->print_cr("    C_const_init = %d", C_const_init);
    +      tty->print_cr("    C_init = abs(scale)= %d", C_init);
    +    }
    +    if (_invar != nullptr) {
    +      tty->print_cr("  invariant present:");
    +      tty->print_cr("    C_invar = abs(invar_factor) = %d", C_invar);
    +    } else {
    +      tty->print_cr("  no invariant:");
    +      tty->print_cr("    C_invar = %d", C_invar);
    +    }
    +    tty->print_cr("  C_const = offset(%d) + scale(%d) * C_const_init(%d) = %d",
    +                  _offset, _scale, C_const_init, C_const);
    +    tty->print_cr("  C_pre   = scale(%d) * pre_stride(%d) = %d",
    +                  _scale, _pre_stride, C_pre);
    +    tty->print_cr("  C_main  = scale(%d) * main_stride(%d) = %d",
    +                  _scale, _main_stride, C_main);
    +  }
    +}
    +
    +void AlignmentSolver::trace_main_iteration_alignment(const int C_const,
    +                                                     const int C_invar,
    +                                                     const int C_init,
    +                                                     const int C_pre,
    +                                                     const int C_main,
    +                                                     const int C_main_mod_aw) const
    +{
    +  if (is_trace()) {
    +    tty->print("  EQ(1 ): (C_const(%d) + C_invar(%d) * var_invar + C_init(%d) * var_init",
    +                  C_const, C_invar, C_init);
    +    tty->print(" + C_pre(%d) * pre_iter + C_main(%d) * main_iter) %% aw(%d) = 0",
    +                  C_pre, C_main, _aw);
    +    tty->print_cr(" (given base aligned -> align rest)");
    +    tty->print("  EQ(2 ): C_main(%d) %% aw(%d) = %d = 0",
    +               C_main, _aw, C_main_mod_aw);
    +    tty->print_cr(" (alignment across iterations)");
    +  }
    +}
    +
    +void AlignmentSolver::EQ4::trace() const {
    +  tty->print_cr("  EQ(4a): (C_const(%3d)             + C_pre(%d) * pre_iter_C_const) %% aw(%d) = 0  (align const term individually)",
    +                _C_const, _C_pre, _aw);
    +  tty->print_cr("          -> %s", state_to_str(eq4a_state()));
    +
    +  tty->print_cr("  EQ(4b): (C_invar(%3d) * var_invar + C_pre(%d) * pre_iter_C_invar) %% aw(%d) = 0  (align invar term individually)",
    +                _C_invar, _C_pre, _aw);
    +  tty->print_cr("          -> %s", state_to_str(eq4b_state()));
    +
    +  tty->print_cr("  EQ(4c): (C_init( %3d) * var_init  + C_pre(%d) * pre_iter_C_init ) %% aw(%d) = 0  (align init term individually)",
    +                _C_init, _C_pre, _aw);
    +  tty->print_cr("          -> %s", state_to_str(eq4c_state()));
    +}
    +
    +void AlignmentSolver::trace_constrained_solution(const int C_const,
    +                                                 const int C_invar,
    +                                                 const int C_init,
    +                                                 const int C_pre,
    +                                                 const int q,
    +                                                 const int r) const
    +{
    +  if (is_trace()) {
    +    tty->print_cr("  EQ(4a, b, c) all constrained, hence:");
    +    tty->print_cr("  EQ(5a): C_const(%3d) %% abs(C_pre(%d)) = 0", C_const, C_pre);
    +    tty->print_cr("  EQ(5b): C_invar(%3d) %% abs(C_pre(%d)) = 0", C_invar, C_pre);
    +    tty->print_cr("  EQ(5c): C_init( %3d) %% abs(C_pre(%d)) = 0", C_init,  C_pre);
    +
    +    tty->print_cr("  All terms in EQ(4a, b, c) are divisible by abs(C_pre(%d)).", C_pre);
    +    const int X    = C_const / abs(C_pre);
    +    const int Y    = C_invar / abs(C_pre);
    +    const int Z    = C_init  / abs(C_pre);
    +    const int sign = (C_pre > 0) ? 1 : -1;
    +    tty->print_cr("  X = C_const(%3d) / abs(C_pre(%d)) = %d       (6a)", C_const, C_pre, X);
    +    tty->print_cr("  Y = C_invar(%3d) / abs(C_pre(%d)) = %d       (6b)", C_invar, C_pre, Y);
    +    tty->print_cr("  Z = C_init( %3d) / abs(C_pre(%d)) = %d       (6c)", C_init , C_pre, Z);
    +    tty->print_cr("  q = aw(     %3d) / abs(C_pre(%d)) = %d       (8)",  _aw,     C_pre, q);
    +    tty->print_cr("  sign(C_pre) = (C_pre(%d) > 0) ? 1 : -1 = %d  (7)",  C_pre,   sign);
    +
    +    tty->print_cr("  EQ(9a): (X(%3d)             + pre_iter_C_const * sign(C_pre)) %% q(%d) = 0", X, q);
    +    tty->print_cr("  EQ(9b): (Y(%3d) * var_invar + pre_iter_C_invar * sign(C_pre)) %% q(%d) = 0", Y, q);
    +    tty->print_cr("  EQ(9c): (Z(%3d) * var_init  + pre_iter_C_init  * sign(C_pre)) %% q(%d) = 0", Z, q);
    +
    +    tty->print_cr("  EQ(10a): pre_iter_C_const = mx2 * q(%d) - sign(C_pre) * X(%d)",             q, X);
    +    tty->print_cr("  EQ(10b): pre_iter_C_invar = my2 * q(%d) - sign(C_pre) * Y(%d) * var_invar", q, Y);
    +    tty->print_cr("  EQ(10c): pre_iter_C_init  = mz2 * q(%d) - sign(C_pre) * Z(%d) * var_init ", q, Z);
    +
    +    tty->print_cr("  r = (-C_const(%d) / (scale(%d) * pre_stride(%d)) %% q(%d) = %d",
    +                  C_const, _scale, _pre_stride, q, r);
    +
    +    tty->print_cr("  EQ(14):  pre_iter = m * q(%3d) - r(%d)", q, r);
    +    if (_invar != nullptr) {
    +      tty->print_cr("                                 - invar / (scale(%d) * pre_stride(%d))",
    +                    _scale, _pre_stride);
    +    }
    +    if (!_init_node->is_ConI()) {
    +      tty->print_cr("                                 - init / pre_stride(%d)",
    +                    _pre_stride);
    +    }
    +  }
    +}
     #endif
    diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp
    index 8df5d0c9a82..8e63b40d5ac 100644
    --- a/src/hotspot/share/opto/vectorization.hpp
    +++ b/src/hotspot/share/opto/vectorization.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
      * Copyright (c) 2023, Arm Limited. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
    @@ -36,7 +36,7 @@
     // operation in a counted loop for vectorizable analysis.
     class VPointer : public ArenaObj {
      protected:
    -  MemNode*        _mem;      // My memory reference node
    +  const MemNode*  _mem;      // My memory reference node
       PhaseIdealLoop* _phase;    // PhaseIdealLoop handle
       IdealLoopTree*  _lpt;      // Current IdealLoopTree
       PhiNode*        _iv;       // The loop induction variable
    @@ -80,23 +80,27 @@ class VPointer : public ArenaObj {
         NotComparable = (Less | Greater | Equal)
       };
     
    -  VPointer(MemNode* mem, PhaseIdealLoop* phase, IdealLoopTree* lpt,
    -            Node_Stack* nstack, bool analyze_only);
    +  VPointer(const MemNode* mem,
    +           PhaseIdealLoop* phase, IdealLoopTree* lpt,
    +           Node_Stack* nstack, bool analyze_only);
       // Following is used to create a temporary object during
       // the pattern match of an address expression.
       VPointer(VPointer* p);
     
    -  bool valid()  { return _adr != nullptr; }
    -  bool has_iv() { return _scale != 0; }
    +  bool valid()             const { return _adr != nullptr; }
    +  bool has_iv()            const { return _scale != 0; }
     
    -  Node* base()             { return _base; }
    -  Node* adr()              { return _adr; }
    -  MemNode* mem()           { return _mem; }
    -  int   scale_in_bytes()   { return _scale; }
    -  Node* invar()            { return _invar; }
    -  int   offset_in_bytes()  { return _offset; }
    -  int   memory_size()      { return _mem->memory_size(); }
    -  Node_Stack* node_stack() { return _nstack; }
    +  Node* base()             const { return _base; }
    +  Node* adr()              const { return _adr; }
    +  const MemNode* mem()     const { return _mem; }
    +  int   scale_in_bytes()   const { return _scale; }
    +  Node* invar()            const { return _invar; }
    +  int   offset_in_bytes()  const { return _offset; }
    +  int   memory_size()      const { return _mem->memory_size(); }
    +  Node_Stack* node_stack() const { return _nstack; }
    +
    +  // Biggest detectable factor of the invariant.
    +  int   invar_factor() const;
     
       // Comparable?
       bool invar_equals(VPointer& q) {
    @@ -165,12 +169,12 @@ class VPointer : public ArenaObj {
         Tracer(bool is_trace_alignment) : _is_trace_alignment(is_trace_alignment) {}
     
         // tracing functions
    -    void ctor_1(Node* mem);
    +    void ctor_1(const Node* mem);
         void ctor_2(Node* adr);
         void ctor_3(Node* adr, int i);
         void ctor_4(Node* adr, int i);
         void ctor_5(Node* adr, Node* base,  int i);
    -    void ctor_6(Node* mem);
    +    void ctor_6(const Node* mem);
     
         void scaled_iv_plus_offset_1(Node* n);
         void scaled_iv_plus_offset_2(Node* n);
    @@ -259,4 +263,419 @@ class VectorElementSizeStats {
       }
     };
     
    +// When alignment is required, we must adjust the pre-loop iteration count pre_iter,
    +// such that the address is aligned for any main_iter >= 0:
    +//
    +//   adr = base + offset + invar + scale * init
    +//                               + scale * pre_stride * pre_iter
    +//                               + scale * main_stride * main_iter
    +//
    +// The AlignmentSolver generates solutions of the following forms:
    +//   1. Empty:       No pre_iter guarantees alignment.
    +//   2. Trivial:     Any pre_iter guarantees alignment.
    +//   3. Constrained: There is a periodic solution, but it is not trivial.
    +//
    +// The Constrained solution is of the following form:
    +//
    +//   pre_iter = m * q + r                                    (for any integer m)
    +//                   [- invar / (scale * pre_stride)  ]      (if there is an invariant)
    +//                   [- init / pre_stride             ]      (if init is variable)
    +//
    +// The solution is periodic with periodicity q, which is guaranteed to be a power of 2.
    +// This periodic solution is "rotated" by three alignment terms: one for constants (r),
    +// one for the invariant (if present), and one for init (if it is variable).
    +//
    +// The "filter" method combines the solutions of two mem_refs, such that the new set of
    +// values for pre_iter guarantees alignment for both mem_refs.
    +//
    +class EmptyAlignmentSolution;
    +class TrivialAlignmentSolution;
    +class ConstrainedAlignmentSolution;
    +
    +class AlignmentSolution : public ResourceObj {
    +public:
    +  virtual bool is_empty() const = 0;
    +  virtual bool is_trivial() const = 0;
    +  virtual bool is_constrained() const = 0;
    +
    +  virtual const ConstrainedAlignmentSolution* as_constrained() const {
    +    assert(is_constrained(), "must be constrained");
    +    return nullptr;
    +  }
    +
    +  // Implemented by each subclass
    +  virtual const AlignmentSolution* filter(const AlignmentSolution* other) const = 0;
    +  virtual void print() const = 0;
    +
    +  // Compute modulo and ensure that we get a positive remainder
    +  static int mod(int i, int q) {
    +    assert(q >= 1, "modulo value must be large enough");
    +
    +    // Modulo operator: Get positive 0 <= r < q  for positive i, but
    +    //                  get negative 0 >= r > -q for negative i.
    +    int r = i % q;
    +
    +    // Make negative r into positive ones:
    +    r = (r >= 0) ? r : r + q;
    +
    +    assert(0 <= r && r < q, "remainder must fit in modulo space");
    +    return r;
    +  }
    +};
    +
    +class EmptyAlignmentSolution : public AlignmentSolution {
    +private:
    +  const char* _reason;
    +public:
    +  EmptyAlignmentSolution(const char* reason) :  _reason(reason) {}
    +  virtual bool is_empty() const override final       { return true; }
    +  virtual bool is_trivial() const override final     { return false; }
    +  virtual bool is_constrained() const override final { return false; }
    +  const char* reason() const { return _reason; }
    +
    +  virtual const AlignmentSolution* filter(const AlignmentSolution* other) const override final {
    +    // If "this" cannot be guaranteed to be aligned, then we also cannot guarantee to align
    +    // "this" and "other" together.
    +    return new EmptyAlignmentSolution("empty solution input to filter");
    +  }
    +
    +  virtual void print() const override final {
    +    tty->print_cr("empty solution: %s", reason());
    +  };
    +};
    +
    +class TrivialAlignmentSolution : public AlignmentSolution {
    +public:
    +  TrivialAlignmentSolution() {}
    +  virtual bool is_empty() const override final       { return false; }
    +  virtual bool is_trivial() const override final     { return true; }
    +  virtual bool is_constrained() const override final { return false; }
    +
    +  virtual const AlignmentSolution* filter(const AlignmentSolution* other) const override final {
    +    if (other->is_empty()) {
    +      // If "other" cannot be guaranteed to be aligned, then we also cannot guarantee to align
    +      // "this" and "other".
    +      return new EmptyAlignmentSolution("empty solution input to filter");
    +    }
    +    // Since "this" is trivial (no constraints), the solution of "other" guarantees alignment
    +    // of both.
    +    return other;
    +  }
    +
    +  virtual void print() const override final {
    +    tty->print_cr("pre_iter >= 0 (trivial)");
    +  };
    +};
    +
    +class ConstrainedAlignmentSolution : public AlignmentSolution {
    +private:
    +  const MemNode* _mem_ref;
    +  const int _q;
    +  const int _r;
    +  const Node* _invar;
    +  const int _scale;
    +public:
    +  ConstrainedAlignmentSolution(const MemNode* mem_ref,
    +                               const int q,
    +                               const int r,
    +                               const Node* invar,
    +                               int scale) :
    +      _mem_ref(mem_ref),
    +      _q(q),
    +      _r(r),
    +      _invar(invar),
    +      _scale(scale) {
    +    assert(q > 1 && is_power_of_2(q), "q must be power of 2");
    +    assert(0 <= r && r < q, "r must be in modulo space of q");
    +    assert(_mem_ref != nullptr, "must have mem_ref");
    +  }
    +
    +  virtual bool is_empty() const override final       { return false; }
    +  virtual bool is_trivial() const override final     { return false; }
    +  virtual bool is_constrained() const override final { return true; }
    +
    +  const MemNode* mem_ref() const        { return _mem_ref; }
    +
    +  virtual const ConstrainedAlignmentSolution* as_constrained() const override final { return this; }
    +
    +  virtual const AlignmentSolution* filter(const AlignmentSolution* other) const override final {
    +    if (other->is_empty()) {
    +      // If "other" cannot be guaranteed to be aligned, then we also cannot guarantee to align
    +      // "this" and "other" together.
    +      return new EmptyAlignmentSolution("empty solution input to filter");
    +    }
    +    // Since "other" is trivial (no constraints), the solution of "this" guarantees alignment
    +    // of both.
    +    if (other->is_trivial()) {
    +      return this;
    +    }
    +
    +    // Both solutions are constrained:
    +    ConstrainedAlignmentSolution const* s1 = this;
    +    ConstrainedAlignmentSolution const* s2 = other->as_constrained();
    +
    +    // Thus, pre_iter is the intersection of two sets, i.e. constrained by these two equations,
    +    // for any integers m1 and m2:
    +    //
    +    //   pre_iter = m1 * q1 + r1
    +    //                     [- invar1 / (scale1 * pre_stride)  ]
    +    //                     [- init / pre_stride               ]
    +    //
    +    //   pre_iter = m2 * q2 + r2
    +    //                     [- invar2 / (scale2 * pre_stride)  ]
    +    //                     [- init / pre_stride               ]
    +    //
    +    // Note: pre_stride and init are identical for all mem_refs in the loop.
    +    //
    +    // The init alignment term either does not exist for both mem_refs, or exists identically
    +    // for both. The init alignment term is thus trivially identical.
    +    //
    +    // The invar alignment term is identical if either:
    +    //   - both mem_refs have no invariant.
    +    //   - both mem_refs have the same invariant and the same scale.
    +    //
    +    if (s1->_invar != s2->_invar) {
    +      return new EmptyAlignmentSolution("invar not identical");
    +    }
    +    if (s1->_invar != nullptr && s1->_scale != s2->_scale) {
    +      return new EmptyAlignmentSolution("has invar with different scale");
    +    }
    +
    +    // Now, we have reduced the problem to:
    +    //
    +    //   pre_iter = m1 * q1 + r1 [- x]       (S1)
    +    //   pre_iter = m2 * q2 + r2 [- x]       (S2)
    +    //
    +
    +    // Make s2 the bigger modulo space, i.e. has larger periodicity q.
    +    // This guarantees that S2 is either identical to, a subset of,
    +    // or disjunct from S1 (but cannot be a strict superset of S1).
    +    if (s1->_q > s2->_q) {
    +      swap(s1, s2);
    +    }
    +    assert(s1->_q <= s2->_q, "s1 is a smaller modulo space than s2");
    +
    +    // Is S2 subset of (or equal to) S1?
    +    //
    +    // for any m2, there are integers a, b, m1: m2 * q2     + r2          =
    +    //                                          m2 * a * q1 + b * q1 + r1 =
    +    //                                          (m2 * a + b) * q1 + r1
    +    //
    +    // Since q1 and q2 are both powers of 2, and q1 <= q2, we know there
    +    // is an integer a: a * q1 = q2. Thus, it remains to check if there
    +    // is an integer b: b * q1 + r1 = r2. This is equivalent to checking:
    +    //
    +    //   r1 = r1 % q1 = r2 % q1
    +    //
    +    if (mod(s2->_r, s1->_q) != s1->_r) {
    +      // Neither is subset of the other -> no intersection
    +      return new EmptyAlignmentSolution("empty intersection (r and q)");
    +    }
    +
    +    // Now we know: "s1 = m1 * q1 + r1" is a superset of "s2 = m2 * q2 + r2"
    +    // Hence, any solution of S2 guarantees alignment for both mem_refs.
    +    return s2; // return the subset
    +  }
    +
    +  virtual void print() const override final {
    +    tty->print("m * q(%d) + r(%d)", _q, _r);
    +    if (_invar != nullptr) {
    +      tty->print(" - invar[%d] / (scale(%d) * pre_stride)", _invar->_idx, _scale);
    +    }
    +    tty->print_cr(" [- init / pre_stride], mem_ref[%d]", mem_ref()->_idx);
    +  };
    +};
    +
    +// When strict alignment is required (e.g. -XX:+AlignVector), then we must ensure
    +// that all vector memory accesses can be aligned. We achieve this alignment by
    +// adjusting the pre-loop limit, which adjusts the number of iterations executed
    +// in the pre-loop.
    +//
    +// This is how the pre-loop and unrolled main-loop look like for a memref (adr):
    +//
    +// iv = init
    +// i = 0 // single-iteration counter
    +//
    +// pre-loop:
    +//   iv = init + i * pre_stride
    +//   adr = base + offset + invar + scale * iv
    +//   adr = base + offset + invar + scale * (init + i * pre_stride)
    +//   iv += pre_stride
    +//   i++
    +//
    +// pre_iter = i // number of iterations in the pre-loop
    +// iv = init + pre_iter * pre_stride
    +//
    +// main_iter = 0 // main-loop iteration counter
    +// main_stride = unroll_factor * pre_stride
    +//
    +// main-loop:
    +//   i = pre_iter + main_iter * unroll_factor
    +//   iv = init + i * pre_stride = init + pre_iter * pre_stride + main_iter * unroll_factor * pre_stride
    +//                              = init + pre_iter * pre_stride + main_iter * main_stride
    +//   adr = base + offset + invar + scale * iv // must be aligned
    +//   iv += main_stride
    +//   i  += unroll_factor
    +//   main_iter++
    +//
    +// For each vector memory access, we can find the set of pre_iter (number of pre-loop
    +// iterations) which would align its address. The AlignmentSolver finds such an
    +// AlignmentSolution. We can then check which solutions are compatible, and thus
    +// decide if we have to (partially) reject vectorization if not all vectors have
    +// a compatible solutions.
    +class AlignmentSolver {
    +private:
    +  const MemNode* _mem_ref;       // first element
    +  const uint     _vector_length; // number of elements in vector
    +  const int      _element_size;
    +  const int      _vector_width;  // in bytes
    +
    +  // All vector loads and stores need to be memory aligned. The alignment width (aw) in
    +  // principle is the vector_width. But when vector_width > ObjectAlignmentInBytes this is
    +  // too strict, since any memory object is only guaranteed to be ObjectAlignmentInBytes
    +  // aligned. For example, the relative offset between two arrays is only guaranteed to
    +  // be divisible by ObjectAlignmentInBytes.
    +  const int      _aw;
    +
    +  // We analyze the address of mem_ref. The idea is to disassemble it into a linear
    +  // expression, where we can use the constant factors as the basis for ensuring the
    +  // alignment of vector memory accesses.
    +  //
    +  // The Simple form of the address is disassembled by VPointer into:
    +  //
    +  //   adr = base + offset + invar + scale * iv
    +  //
    +  // Where the iv can be written as:
    +  //
    +  //   iv = init + pre_stride * pre_iter + main_stride * main_iter
    +  //
    +  // pre_iter:    number of pre-loop iterations (adjustable via pre-loop limit)
    +  // main_iter:   number of main-loop iterations (main_iter >= 0)
    +  //
    +  const Node*    _base;           // base of address (e.g. Java array object, aw-aligned)
    +  const int      _offset;
    +  const Node*    _invar;
    +  const int      _invar_factor;   // known constant factor of invar
    +  const int      _scale;
    +  const Node*    _init_node;      // value of iv before pre-loop
    +  const int      _pre_stride;     // address increment per pre-loop iteration
    +  const int      _main_stride;    // address increment per main-loop iteration
    +
    +  DEBUG_ONLY( const bool _is_trace; );
    +
    +  static const MemNode* mem_ref_not_null(const MemNode* mem_ref) {
    +    assert(mem_ref != nullptr, "not nullptr");
    +    return mem_ref;
    +  }
    +
    +public:
    +  AlignmentSolver(const MemNode* mem_ref,
    +                  const uint vector_length,
    +                  const Node* base,
    +                  const int offset,
    +                  const Node* invar,
    +                  const int invar_factor,
    +                  const int scale,
    +                  const Node* init_node,
    +                  const int pre_stride,
    +                  const int main_stride
    +                  DEBUG_ONLY( COMMA const bool is_trace)
    +                  ) :
    +      _mem_ref(           mem_ref_not_null(mem_ref)),
    +      _vector_length(     vector_length),
    +      _element_size(      _mem_ref->memory_size()),
    +      _vector_width(      _vector_length * _element_size),
    +      _aw(                MIN2(_vector_width, ObjectAlignmentInBytes)),
    +      _base(              base),
    +      _offset(            offset),
    +      _invar(             invar),
    +      _invar_factor(      invar_factor),
    +      _scale(             scale),
    +      _init_node(         init_node),
    +      _pre_stride(        pre_stride),
    +      _main_stride(       main_stride)
    +      DEBUG_ONLY( COMMA _is_trace(is_trace) )
    +  {
    +    assert(_mem_ref != nullptr &&
    +           (_mem_ref->is_Load() || _mem_ref->is_Store()),
    +           "only load or store vectors allowed");
    +  }
    +
    +  AlignmentSolution* solve() const;
    +
    +private:
    +  class EQ4 {
    +   private:
    +    const int _C_const;
    +    const int _C_invar;
    +    const int _C_init;
    +    const int _C_pre;
    +    const int _aw;
    +
    +   public:
    +    EQ4(const int C_const, const int C_invar, const int C_init, const int C_pre, const int aw) :
    +    _C_const(C_const), _C_invar(C_invar), _C_init(C_init), _C_pre(C_pre), _aw(aw) {}
    +
    +    enum State { TRIVIAL, CONSTRAINED, EMPTY };
    +
    +    State eq4a_state() const {
    +      return (abs(_C_pre) >= _aw) ? ( (C_const_mod_aw() == 0       ) ? TRIVIAL     : EMPTY)
    +                                  : ( (C_const_mod_abs_C_pre() == 0) ? CONSTRAINED : EMPTY);
    +    }
    +
    +    State eq4b_state() const {
    +      return (abs(_C_pre) >= _aw) ? ( (C_invar_mod_aw() == 0       ) ? TRIVIAL     : EMPTY)
    +                                  : ( (C_invar_mod_abs_C_pre() == 0) ? CONSTRAINED : EMPTY);
    +    }
    +
    +    State eq4c_state() const {
    +      return (abs(_C_pre) >= _aw) ? ( (C_init_mod_aw() == 0       )  ? TRIVIAL     : EMPTY)
    +                                  : ( (C_init_mod_abs_C_pre() == 0)  ? CONSTRAINED : EMPTY);
    +    }
    +
    +   private:
    +    int C_const_mod_aw() const        { return AlignmentSolution::mod(_C_const, _aw); }
    +    int C_invar_mod_aw() const        { return AlignmentSolution::mod(_C_invar, _aw); }
    +    int C_init_mod_aw() const         { return AlignmentSolution::mod(_C_init,  _aw); }
    +    int C_const_mod_abs_C_pre() const { return AlignmentSolution::mod(_C_const, abs(_C_pre)); }
    +    int C_invar_mod_abs_C_pre() const { return AlignmentSolution::mod(_C_invar, abs(_C_pre)); }
    +    int C_init_mod_abs_C_pre() const  { return AlignmentSolution::mod(_C_init,  abs(_C_pre)); }
    +
    +#ifdef ASSERT
    +   public:
    +    void trace() const;
    +
    +   private:
    +    static const char* state_to_str(State s) {
    +      if (s == TRIVIAL)     { return "trivial"; }
    +      if (s == CONSTRAINED) { return "constrained"; }
    +      return "empty";
    +    }
    +#endif
    +  };
    +
    +#ifdef ASSERT
    +  bool is_trace() const { return _is_trace; }
    +  void trace_start_solve() const;
    +  void trace_reshaped_form(const int C_const,
    +                           const int C_const_init,
    +                           const int C_invar,
    +                           const int C_init,
    +                           const int C_pre,
    +                           const int C_main) const;
    +  void trace_main_iteration_alignment(const int C_const,
    +                                      const int C_invar,
    +                                      const int C_init,
    +                                      const int C_pre,
    +                                      const int C_main,
    +                                      const int C_main_mod_aw) const;
    +  void trace_constrained_solution(const int C_const,
    +                                  const int C_invar,
    +                                  const int C_init,
    +                                  const int C_pre,
    +                                  const int q,
    +                                  const int r) const;
    +#endif
    +};
    +
     #endif // SHARE_OPTO_VECTORIZATION_HPP
    diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp
    index 6992f3516aa..e4d3d013cd3 100644
    --- a/src/hotspot/share/opto/vectornode.hpp
    +++ b/src/hotspot/share/opto/vectornode.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -847,6 +847,8 @@ class ExpandVNode: public VectorNode {
     //------------------------------LoadVectorNode---------------------------------
     // Load Vector from memory
     class LoadVectorNode : public LoadNode {
    + private:
    +  DEBUG_ONLY( bool _must_verify_alignment = false; );
      public:
       LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, ControlDependency control_dependency = LoadNode::DependsOnlyOnTest)
         : LoadNode(c, mem, adr, at, vt, MemNode::unordered, control_dependency) {
    @@ -871,6 +873,17 @@ class LoadVectorNode : public LoadNode {
                                   uint vlen, BasicType bt,
                                   ControlDependency control_dependency = LoadNode::DependsOnlyOnTest);
       uint element_size(void) { return type2aelembytes(vect_type()->element_basic_type()); }
    +
    +  // Needed for proper cloning.
    +  virtual uint size_of() const { return sizeof(*this); }
    +
    +#ifdef ASSERT
    +  // When AlignVector is enabled, SuperWord only creates aligned vector loads and stores.
    +  // VerifyAlignVector verifies this. We need to mark the nodes created in SuperWord,
    +  // because nodes created elsewhere (i.e. VectorAPI) may still be misaligned.
    +  bool must_verify_alignment() const { return _must_verify_alignment; }
    +  void set_must_verify_alignment() { _must_verify_alignment = true; }
    +#endif
     };
     
     //------------------------------LoadVectorGatherNode------------------------------
    @@ -894,6 +907,7 @@ class LoadVectorGatherNode : public LoadVectorNode {
     class StoreVectorNode : public StoreNode {
      private:
       const TypeVect* _vect_type;
    +  DEBUG_ONLY( bool _must_verify_alignment = false; );
      public:
       StoreVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val)
         : StoreNode(c, mem, adr, at, val, MemNode::unordered), _vect_type(val->bottom_type()->is_vect()) {
    @@ -918,6 +932,14 @@ class StoreVectorNode : public StoreNode {
     
       // Needed for proper cloning.
       virtual uint size_of() const { return sizeof(*this); }
    +
    +#ifdef ASSERT
    +  // When AlignVector is enabled, SuperWord only creates aligned vector loads and stores.
    +  // VerifyAlignVector verifies this. We need to mark the nodes created in SuperWord,
    +  // because nodes created elsewhere (i.e. VectorAPI) may still be misaligned.
    +  bool must_verify_alignment() const { return _must_verify_alignment; }
    +  void set_must_verify_alignment() { _must_verify_alignment = true; }
    +#endif
     };
     
     //------------------------------StoreVectorScatterNode------------------------------
    @@ -1017,6 +1039,25 @@ class StoreVectorScatterMaskedNode : public StoreVectorNode {
                                                         idx == MemNode::ValueIn + 2; }
     };
     
    +// Verify that memory address (adr) is aligned. The mask specifies the
    +// least significant bits which have to be zero in the address.
    +//
    +// if (adr & mask == 0) {
    +//   return adr
    +// } else {
    +//   stop("verify_vector_alignment found a misaligned vector memory access")
    +// }
    +//
    +// This node is used just before a vector load/store with -XX:+VerifyAlignVector
    +class VerifyVectorAlignmentNode : public Node {
    +  virtual uint hash() const { return NO_HASH; };
    +public:
    +  VerifyVectorAlignmentNode(Node* adr, Node* mask) : Node(nullptr, adr, mask) {}
    +  virtual int Opcode() const;
    +  virtual uint size_of() const { return sizeof(*this); }
    +  virtual const Type *bottom_type() const { return in(1)->bottom_type(); }
    +};
    +
     //------------------------------VectorCmpMaskedNode--------------------------------
     // Vector Comparison under the influence of a predicate register(mask).
     class VectorCmpMaskedNode : public TypeNode {
    diff --git a/src/hotspot/share/prims/foreignGlobals.cpp b/src/hotspot/share/prims/foreignGlobals.cpp
    index f3653d29886..11b0b8ace7c 100644
    --- a/src/hotspot/share/prims/foreignGlobals.cpp
    +++ b/src/hotspot/share/prims/foreignGlobals.cpp
    @@ -140,7 +140,7 @@ int ForeignGlobals::compute_out_arg_bytes(const GrowableArray& out_re
     
     int ForeignGlobals::java_calling_convention(const BasicType* signature, int num_args, GrowableArray& out_regs) {
       VMRegPair* vm_regs = NEW_RESOURCE_ARRAY(VMRegPair, num_args);
    -  int slots = SharedRuntime::java_calling_convention(signature, vm_regs, num_args);
    +  int slots = align_up(SharedRuntime::java_calling_convention(signature, vm_regs, num_args), 2);
       for (int i = 0; i < num_args; i++) {
         VMRegPair pair = vm_regs[i];
         // note, we ignore second here. Signature should consist of register-size values. So there should be
    diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp
    index e722d701945..c0f83bebbff 100644
    --- a/src/hotspot/share/prims/jvm.cpp
    +++ b/src/hotspot/share/prims/jvm.cpp
    @@ -4044,8 +4044,6 @@ JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread))
         // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
         JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false);
       }
    -#else
    -  fatal("Should only be called with JVMTI enabled");
     #endif
     JVM_END
     
    @@ -4061,8 +4059,6 @@ JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread))
         // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
         JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true);
       }
    -#else
    -  fatal("Should only be called with JVMTI enabled");
     #endif
     JVM_END
     
    @@ -4080,8 +4076,6 @@ JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hi
         // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
         JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide);
       }
    -#else
    -  fatal("Should only be called with JVMTI enabled");
     #endif
     JVM_END
     
    @@ -4099,8 +4093,6 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean
         // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
         JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide);
       }
    -#else
    -  fatal("Should only be called with JVMTI enabled");
     #endif
     JVM_END
     
    @@ -4114,8 +4106,20 @@ JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboole
       assert(!thread->is_in_VTMS_transition(), "sanity check");
       assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check");
       thread->toggle_is_in_tmp_VTMS_transition();
    -#else
    -  fatal("Should only be called with JVMTI enabled");
    +#endif
    +JVM_END
    +
    +// Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section.
    +// Needed to avoid deadlocks with JVMTI suspend mechanism.
    +JVM_ENTRY(void, JVM_VirtualThreadDisableSuspend(JNIEnv* env, jobject vthread, jboolean enter))
    +#if INCLUDE_JVMTI
    +  if (!DoJVMTIVirtualThreadTransitions) {
    +    assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
    +    return;
    +  }
    +  assert(thread->is_disable_suspend() != (bool)enter,
    +         "nested or unbalanced monitor enter/exit is not allowed");
    +  thread->toggle_is_disable_suspend();
     #endif
     JVM_END
     
    diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp
    index 9d6296ee316..6a3ee718709 100644
    --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp
    +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -2407,6 +2407,7 @@ UpdateForPopTopFrameClosure::doit(Thread *target, bool self) {
     void
     SetFramePopClosure::do_thread(Thread *target) {
       Thread* current = Thread::current();
    +  ResourceMark rm(current); // vframes are resource allocated
       JavaThread* java_thread = JavaThread::cast(target);
     
       if (java_thread->is_exiting()) {
    @@ -2433,6 +2434,9 @@ SetFramePopClosure::do_thread(Thread *target) {
     
     void
     SetFramePopClosure::do_vthread(Handle target_h) {
    +  Thread* current = Thread::current();
    +  ResourceMark rm(current); // vframes are resource allocated
    +
       if (!_self && !JvmtiVTSuspender::is_vthread_suspended(target_h())) {
         _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
         return;
    diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp
    index ef8aeab3c30..8fd04d7111f 100644
    --- a/src/hotspot/share/prims/unsafe.cpp
    +++ b/src/hotspot/share/prims/unsafe.cpp
    @@ -523,7 +523,10 @@ UNSAFE_ENTRY_SCOPED(void, Unsafe_SetMemory0(JNIEnv *env, jobject unsafe, jobject
       oop base = JNIHandles::resolve(obj);
       void* p = index_oop_from_field_offset_long(base, offset);
     
    -  Copy::fill_to_memory_atomic(p, sz, value);
    +  {
    +    GuardUnsafeAccess guard(thread);
    +    Copy::fill_to_memory_atomic(p, sz, value);
    +  }
     } UNSAFE_END
     
     UNSAFE_ENTRY_SCOPED(void, Unsafe_CopyMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size)) {
    diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
    index dbcf9662580..b5f22bcfe2c 100644
    --- a/src/hotspot/share/runtime/arguments.cpp
    +++ b/src/hotspot/share/runtime/arguments.cpp
    @@ -316,7 +316,6 @@ static bool matches_property_suffix(const char* option, const char* property, si
     // any of the reserved module properties.
     // property should be passed without the leading "-D".
     bool Arguments::is_internal_module_property(const char* property) {
    -  assert((strncmp(property, "-D", 2) != 0), "Unexpected leading -D");
       if  (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) {
         const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN;
         if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) ||
    @@ -526,14 +525,8 @@ static SpecialFlag const special_jvm_flags[] = {
       { "G1ConcRSHotCardLimit",         JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() },
       { "RefDiscoveryPolicy",           JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() },
       { "MetaspaceReclaimPolicy",       JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() },
    -  { "DoReserveCopyInSuperWord",     JDK_Version::undefined(), JDK_Version::jdk(22), JDK_Version::jdk(23) },
    -  { "UseCounterDecay",              JDK_Version::undefined(), JDK_Version::jdk(22), JDK_Version::jdk(23) },
    -
    -#ifdef LINUX
    -  { "UseHugeTLBFS",                 JDK_Version::undefined(), JDK_Version::jdk(22), JDK_Version::jdk(23) },
    -  { "UseSHM",                       JDK_Version::undefined(), JDK_Version::jdk(22), JDK_Version::jdk(23) },
    -#endif
     
    +  { "AdaptiveSizePolicyCollectionCostMargin",   JDK_Version::undefined(), JDK_Version::jdk(23), JDK_Version::jdk(24) },
     #ifdef ASSERT
       { "DummyObsoleteTestFlag",        JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() },
     #endif
    @@ -2295,10 +2288,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin
         // -bootclasspath/a:
         } else if (match_option(option, "-Xbootclasspath/a:", &tail)) {
           Arguments::append_sysclasspath(tail);
    -#if INCLUDE_CDS
    -      MetaspaceShared::disable_optimized_module_handling();
    -      log_info(cds)("optimized module handling: disabled because bootclasspath was appended");
    -#endif
         // -bootclasspath/p:
         } else if (match_option(option, "-Xbootclasspath/p:", &tail)) {
             jio_fprintf(defaultStream::output_stream(),
    @@ -2668,9 +2657,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin
         // -Xdebug
         } else if (match_option(option, "-Xdebug")) {
           warning("Option -Xdebug was deprecated in JDK 22 and will likely be removed in a future release.");
    -    // -Xnoagent
    -    } else if (match_option(option, "-Xnoagent")) {
    -      warning("Option -Xnoagent was deprecated in JDK 22 and will likely be removed in a future release.");
         } else if (match_option(option, "-Xloggc:", &tail)) {
           // Deprecated flag to redirect GC output to a file. -Xloggc:
           log_warning(gc)("-Xloggc is deprecated. Will use -Xlog:gc:%s instead.", tail);
    diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
    index fe1dfc62ee4..26c915852e5 100644
    --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp
    +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
    @@ -1498,21 +1498,21 @@ static void jvmti_yield_cleanup(JavaThread* thread, ContinuationWrapper& cont) {
     #endif // INCLUDE_JVMTI
     
     #ifdef ASSERT
    -// static bool monitors_on_stack(JavaThread* thread) {
    -//   ContinuationEntry* ce = thread->last_continuation();
    -//   RegisterMap map(thread,
    -//                   RegisterMap::UpdateMap::include,
    -//                   RegisterMap::ProcessFrames::include,
    -//                   RegisterMap::WalkContinuation::skip);
    -//   map.set_include_argument_oops(false);
    -//   for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) {
    -//     if ((f.is_interpreted_frame() && ContinuationHelper::InterpretedFrame::is_owning_locks(f)) ||
    -//         (f.is_compiled_frame() && ContinuationHelper::CompiledFrame::is_owning_locks(map.thread(), &map, f))) {
    -//       return true;
    -//     }
    -//   }
    -//   return false;
    -// }
    +static bool monitors_on_stack(JavaThread* thread) {
    +  ContinuationEntry* ce = thread->last_continuation();
    +  RegisterMap map(thread,
    +                  RegisterMap::UpdateMap::include,
    +                  RegisterMap::ProcessFrames::include,
    +                  RegisterMap::WalkContinuation::skip);
    +  map.set_include_argument_oops(false);
    +  for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) {
    +    if ((f.is_interpreted_frame() && ContinuationHelper::InterpretedFrame::is_owning_locks(f)) ||
    +        (f.is_compiled_frame() && ContinuationHelper::CompiledFrame::is_owning_locks(map.thread(), &map, f))) {
    +      return true;
    +    }
    +  }
    +  return false;
    +}
     
     bool FreezeBase::interpreted_native_or_deoptimized_on_stack() {
       ContinuationEntry* ce = _thread->last_continuation();
    @@ -1575,8 +1575,8 @@ static inline int freeze_internal(JavaThread* current, intptr_t* const sp) {
     
       assert(entry->is_virtual_thread() == (entry->scope(current) == java_lang_VirtualThread::vthread_scope()), "");
     
    -  // assert(monitors_on_stack(current) == ((current->held_monitor_count() - current->jni_monitor_count()) > 0),
    -  //        "Held monitor count and locks on stack invariant: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count());
    +  assert(monitors_on_stack(current) == ((current->held_monitor_count() - current->jni_monitor_count()) > 0),
    +         "Held monitor count and locks on stack invariant: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count());
     
       if (entry->is_pinned() || current->held_monitor_count() > 0) {
         log_develop_debug(continuations)("PINNED due to critical section/hold monitor");
    @@ -1775,7 +1775,7 @@ class ThawBase : public StackObj {
       inline void before_thaw_java_frame(const frame& hf, const frame& caller, bool bottom, int num_frame);
       inline void after_thaw_java_frame(const frame& f, bool bottom);
       inline void patch(frame& f, const frame& caller, bool bottom);
    -  void clear_bitmap_bits(intptr_t* start, int range);
    +  void clear_bitmap_bits(address start, address end);
     
       NOINLINE void recurse_thaw_interpreted_frame(const frame& hf, frame& caller, int num_frames);
       void recurse_thaw_compiled_frame(const frame& hf, frame& caller, int num_frames, bool stub_caller);
    @@ -2166,13 +2166,22 @@ inline void ThawBase::patch(frame& f, const frame& caller, bool bottom) {
       assert(!bottom || (_cont.is_empty() != Continuation::is_cont_barrier_frame(f)), "");
     }
     
    -void ThawBase::clear_bitmap_bits(intptr_t* start, int range) {
    +void ThawBase::clear_bitmap_bits(address start, address end) {
    +  assert(is_aligned(start, wordSize), "should be aligned: " PTR_FORMAT, p2i(start));
    +  assert(is_aligned(end, VMRegImpl::stack_slot_size), "should be aligned: " PTR_FORMAT, p2i(end));
    +
       // we need to clear the bits that correspond to arguments as they reside in the caller frame
    -  // or they will keep objects that are otherwise unreachable alive
    -  log_develop_trace(continuations)("clearing bitmap for " INTPTR_FORMAT " - " INTPTR_FORMAT, p2i(start), p2i(start+range));
    +  // or they will keep objects that are otherwise unreachable alive.
    +
    +  // Align `end` if UseCompressedOops is not set to avoid UB when calculating the bit index, since
    +  // `end` could be at an odd number of stack slots from `start`, i.e might not be oop aligned.
    +  // If that's the case the bit range corresponding to the last stack slot should not have bits set
    +  // anyways and we assert that before returning.
    +  address effective_end = UseCompressedOops ? end : align_down(end, wordSize);
    +  log_develop_trace(continuations)("clearing bitmap for " INTPTR_FORMAT " - " INTPTR_FORMAT, p2i(start), p2i(effective_end));
       stackChunkOop chunk = _cont.tail();
    -  chunk->bitmap().clear_range(chunk->bit_index_for(start),
    -                              chunk->bit_index_for(start+range));
    +  chunk->bitmap().clear_range(chunk->bit_index_for(start), chunk->bit_index_for(effective_end));
    +  assert(chunk->bitmap().count_one_bits(chunk->bit_index_for(effective_end), chunk->bit_index_for(end)) == 0, "bits should not be set");
     }
     
     NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& caller, int num_frames) {
    @@ -2225,7 +2234,9 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c
         _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance);
       } else if (_cont.tail()->has_bitmap() && locals > 0) {
         assert(hf.is_heap_frame(), "should be");
    -    clear_bitmap_bits(heap_frame_bottom - locals, locals);
    +    address start = (address)(heap_frame_bottom - locals);
    +    address end = (address)heap_frame_bottom;
    +    clear_bitmap_bits(start, end);
       }
     
       DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);)
    @@ -2298,7 +2309,10 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n
         // can only fix caller once this frame is thawed (due to callee saved regs); this happens on the stack
         _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance);
       } else if (_cont.tail()->has_bitmap() && added_argsize > 0) {
    -    clear_bitmap_bits(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top, added_argsize);
    +    address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top);
    +    int stack_args_slots = f.cb()->as_compiled_method()->method()->num_stack_arg_slots(false /* rounded */);
    +    int argsize_in_bytes = stack_args_slots * VMRegImpl::stack_slot_size;
    +    clear_bitmap_bits(start, start + argsize_in_bytes);
       }
     
       DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);)
    diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp
    index 9039d71dfd1..f14cf6c6e99 100644
    --- a/src/hotspot/share/runtime/frame.cpp
    +++ b/src/hotspot/share/runtime/frame.cpp
    @@ -1480,7 +1480,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m
             assert(sig_index == sizeargs, "");
           }
           int stack_arg_slots = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs);
    -      assert(stack_arg_slots ==  m->num_stack_arg_slots(), "");
    +      assert(stack_arg_slots ==  m->num_stack_arg_slots(false /* rounded */), "");
           int out_preserve = SharedRuntime::out_preserve_stack_slots();
           int sig_index = 0;
           int arg_index = (m->is_static() ? 0 : -1);
    diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp
    index 09380c6eff2..a91dfc613f9 100644
    --- a/src/hotspot/share/runtime/frame.hpp
    +++ b/src/hotspot/share/runtime/frame.hpp
    @@ -90,6 +90,8 @@ class frame {
       void assert_offset() const   { assert(_frame_index >= 0,  "Using offset with a non-chunk frame"); assert_on_heap(); }
       void assert_absolute() const { assert(_frame_index == -1, "Using absolute addresses with a chunk frame"); }
     
    +  const ImmutableOopMap* get_oop_map() const;
    +
      public:
       // Constructors
       frame();
    diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp
    index 2cfaba17054..da774fe1620 100644
    --- a/src/hotspot/share/runtime/frame.inline.hpp
    +++ b/src/hotspot/share/runtime/frame.inline.hpp
    @@ -104,6 +104,19 @@ inline CodeBlob* frame::get_cb() const {
       return _cb;
     }
     
    +inline const ImmutableOopMap* frame::get_oop_map() const {
    +  if (_cb == nullptr || _cb->oop_maps() == nullptr) return nullptr;
    +
    +  NativePostCallNop* nop = nativePostCallNop_at(_pc);
    +  int oopmap_slot;
    +  int cb_offset;
    +  if (nop != nullptr && nop->decode(oopmap_slot, cb_offset)) {
    +    return _cb->oop_map_for_slot(oopmap_slot, _pc);
    +  }
    +  const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
    +  return oop_map;
    +}
    +
     inline int frame::interpreter_frame_monitor_size_in_bytes() {
       // Number of bytes for a monitor.
       return frame::interpreter_frame_monitor_size() * wordSize;
    diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
    index f286f0eaed9..efc4c4143af 100644
    --- a/src/hotspot/share/runtime/globals.hpp
    +++ b/src/hotspot/share/runtime/globals.hpp
    @@ -546,10 +546,17 @@ const int ObjectAlignmentInBytes = 8;
               "thrown from JVM")                                                \
                                                                                 \
       product(bool, HeapDumpBeforeFullGC, false, MANAGEABLE,                    \
    -          "Dump heap to file before any major stop-the-world GC")           \
    +          "Dump heap to file before any major stop-the-world GC "           \
    +          "(also see FullGCHeapDumpLimit)")                                 \
                                                                                 \
       product(bool, HeapDumpAfterFullGC, false, MANAGEABLE,                     \
    -          "Dump heap to file after any major stop-the-world GC")            \
    +          "Dump heap to file after any major stop-the-world GC "            \
    +          "(also see FullGCHeapDumpLimit)")                                 \
    +                                                                            \
    +  product(uint, FullGCHeapDumpLimit, 0, MANAGEABLE,                         \
    +          "Limit the number of heap dumps triggered by "                    \
    +          "HeapDumpBeforeFullGC or HeapDumpAfterFullGC "                    \
    +          "(0 means no limit)")                                             \
                                                                                 \
       product(bool, HeapDumpOnOutOfMemoryError, false, MANAGEABLE,              \
               "Dump heap to file when java.lang.OutOfMemoryError is thrown "    \
    @@ -888,9 +895,6 @@ const int ObjectAlignmentInBytes = 8;
       develop(bool, TraceBytecodes, false,                                      \
               "Trace bytecode execution")                                       \
                                                                                 \
    -  develop(bool, TraceICs, false,                                            \
    -          "Trace inline cache changes")                                     \
    -                                                                            \
       notproduct(bool, TraceInvocationCounterOverflow, false,                   \
               "Trace method invocation counter overflow")                       \
                                                                                 \
    diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp
    index 50c93d666e2..3919a89789c 100644
    --- a/src/hotspot/share/runtime/handshake.cpp
    +++ b/src/hotspot/share/runtime/handshake.cpp
    @@ -487,6 +487,12 @@ HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend, bool che
       assert(_handshakee == Thread::current(), "Must be called by self");
       assert(_lock.owned_by_self(), "Lock must be held");
       assert(allow_suspend || !check_async_exception, "invalid case");
    +#if INCLUDE_JVMTI
    +  if (allow_suspend && _handshakee->is_disable_suspend()) {
    +    // filter out suspend operations while JavaThread is in disable_suspend mode
    +    allow_suspend = false;
    +  }
    +#endif
       if (!allow_suspend) {
         return _queue.peek(no_suspend_no_async_exception_filter);
       } else if (check_async_exception && !_async_exceptions_blocked) {
    diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp
    index 81f6ab9bcd1..827c7ea9f5a 100644
    --- a/src/hotspot/share/runtime/javaThread.cpp
    +++ b/src/hotspot/share/runtime/javaThread.cpp
    @@ -441,6 +441,7 @@ JavaThread::JavaThread() :
       _carrier_thread_suspended(false),
       _is_in_VTMS_transition(false),
       _is_in_tmp_VTMS_transition(false),
    +  _is_disable_suspend(false),
     #ifdef ASSERT
       _is_VTMS_transition_disabler(false),
     #endif
    diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp
    index 8a44a1347ff..15b8f8574ef 100644
    --- a/src/hotspot/share/runtime/javaThread.hpp
    +++ b/src/hotspot/share/runtime/javaThread.hpp
    @@ -318,6 +318,7 @@ class JavaThread: public Thread {
       volatile bool         _carrier_thread_suspended;       // Carrier thread is externally suspended
       bool                  _is_in_VTMS_transition;          // thread is in virtual thread mount state transition
       bool                  _is_in_tmp_VTMS_transition;      // thread is in temporary virtual thread mount state transition
    +  bool                  _is_disable_suspend;             // JVMTI suspend is temporarily disabled; used on current thread only
     #ifdef ASSERT
       bool                  _is_VTMS_transition_disabler;    // thread currently disabled VTMS transitions
     #endif
    @@ -648,6 +649,9 @@ class JavaThread: public Thread {
       void set_is_in_VTMS_transition(bool val);
       void toggle_is_in_tmp_VTMS_transition()        { _is_in_tmp_VTMS_transition = !_is_in_tmp_VTMS_transition; };
     
    +  bool is_disable_suspend() const                { return _is_disable_suspend; }
    +  void toggle_is_disable_suspend()               { _is_disable_suspend = !_is_disable_suspend; };
    +
     #ifdef ASSERT
       bool is_VTMS_transition_disabler() const       { return _is_VTMS_transition_disabler; }
       void set_is_VTMS_transition_disabler(bool val);
    @@ -816,6 +820,7 @@ class JavaThread: public Thread {
     #if INCLUDE_JVMTI
       static ByteSize is_in_VTMS_transition_offset()     { return byte_offset_of(JavaThread, _is_in_VTMS_transition); }
       static ByteSize is_in_tmp_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_tmp_VTMS_transition); }
    +  static ByteSize is_disable_suspend_offset()        { return byte_offset_of(JavaThread, _is_disable_suspend); }
     #endif
     
       // Returns the jni environment for this thread
    diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp
    index 3f38bcd5ed5..10671d651b1 100644
    --- a/src/hotspot/share/runtime/mutex.hpp
    +++ b/src/hotspot/share/runtime/mutex.hpp
    @@ -221,7 +221,7 @@ class Monitor : public Mutex {
     
     class PaddedMutex : public Mutex {
       enum {
    -    CACHE_LINE_PADDING = (int)DEFAULT_CACHE_LINE_SIZE - (int)sizeof(Mutex),
    +    CACHE_LINE_PADDING = (int)DEFAULT_PADDING_SIZE - (int)sizeof(Mutex),
         PADDING_LEN = CACHE_LINE_PADDING > 0 ? CACHE_LINE_PADDING : 1
       };
       char _padding[PADDING_LEN];
    @@ -232,7 +232,7 @@ class PaddedMutex : public Mutex {
     
     class PaddedMonitor : public Monitor {
       enum {
    -    CACHE_LINE_PADDING = (int)DEFAULT_CACHE_LINE_SIZE - (int)sizeof(Monitor),
    +    CACHE_LINE_PADDING = (int)DEFAULT_PADDING_SIZE - (int)sizeof(Monitor),
         PADDING_LEN = CACHE_LINE_PADDING > 0 ? CACHE_LINE_PADDING : 1
       };
       char _padding[PADDING_LEN];
    diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp
    index 2214713aa4b..a8e2e571c5b 100644
    --- a/src/hotspot/share/runtime/objectMonitor.cpp
    +++ b/src/hotspot/share/runtime/objectMonitor.cpp
    @@ -1844,10 +1844,6 @@ int ObjectMonitor::TrySpin(JavaThread* current) {
       ctr = _SpinDuration;
       if (ctr <= 0) return 0;
     
    -  if (NotRunnable(current, static_cast(owner_raw()))) {
    -    return 0;
    -  }
    -
       // We're good to spin ... spin ingress.
       // CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
       // when preparing to LD...CAS _owner, etc and the CAS is likely
    @@ -1933,13 +1929,6 @@ int ObjectMonitor::TrySpin(JavaThread* current) {
         }
         prv = ox;
     
    -    // Abort the spin if the owner is not executing.
    -    // The owner must be executing in order to drop the lock.
    -    // Spinning while the owner is OFFPROC is idiocy.
    -    // Consider: ctr -= RunnablePenalty ;
    -    if (NotRunnable(current, ox)) {
    -      goto Abort;
    -    }
         if (_succ == nullptr) {
           _succ = current;
         }
    @@ -1972,62 +1961,6 @@ int ObjectMonitor::TrySpin(JavaThread* current) {
       return 0;
     }
     
    -// NotRunnable() -- informed spinning
    -//
    -// Don't bother spinning if the owner is not eligible to drop the lock.
    -// Spin only if the owner thread is _thread_in_Java or _thread_in_vm.
    -// The thread must be runnable in order to drop the lock in timely fashion.
    -// If the _owner is not runnable then spinning will not likely be
    -// successful (profitable).
    -//
    -// Beware -- the thread referenced by _owner could have died
    -// so a simply fetch from _owner->_thread_state might trap.
    -// Instead, we use SafeFetchXX() to safely LD _owner->_thread_state.
    -// Because of the lifecycle issues, the _thread_state values
    -// observed by NotRunnable() might be garbage.  NotRunnable must
    -// tolerate this and consider the observed _thread_state value
    -// as advisory.
    -//
    -// Beware too, that _owner is sometimes a BasicLock address and sometimes
    -// a thread pointer.
    -// Alternately, we might tag the type (thread pointer vs basiclock pointer)
    -// with the LSB of _owner.  Another option would be to probabilistically probe
    -// the putative _owner->TypeTag value.
    -//
    -// Checking _thread_state isn't perfect.  Even if the thread is
    -// in_java it might be blocked on a page-fault or have been preempted
    -// and sitting on a ready/dispatch queue.
    -//
    -// The return value from NotRunnable() is *advisory* -- the
    -// result is based on sampling and is not necessarily coherent.
    -// The caller must tolerate false-negative and false-positive errors.
    -// Spinning, in general, is probabilistic anyway.
    -
    -
    -int ObjectMonitor::NotRunnable(JavaThread* current, JavaThread* ox) {
    -  // Check ox->TypeTag == 2BAD.
    -  if (ox == nullptr) return 0;
    -
    -  // Avoid transitive spinning ...
    -  // Say T1 spins or blocks trying to acquire L.  T1._Stalled is set to L.
    -  // Immediately after T1 acquires L it's possible that T2, also
    -  // spinning on L, will see L.Owner=T1 and T1._Stalled=L.
    -  // This occurs transiently after T1 acquired L but before
    -  // T1 managed to clear T1.Stalled.  T2 does not need to abort
    -  // its spin in this circumstance.
    -  intptr_t BlockedOn = SafeFetchN((intptr_t *) &ox->_Stalled, intptr_t(1));
    -
    -  if (BlockedOn == 1) return 1;
    -  if (BlockedOn != 0) {
    -    return BlockedOn != intptr_t(this) && owner_raw() == ox;
    -  }
    -
    -  assert(sizeof(ox->_thread_state == sizeof(int)), "invariant");
    -  int jst = SafeFetch32((int *) &ox->_thread_state, -1);;
    -  // consider also: jst != _thread_in_Java -- but that's overspecific.
    -  return jst == _thread_blocked || jst == _thread_in_native;
    -}
    -
     
     // -----------------------------------------------------------------------------
     // WaitSet management ...
    diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp
    index fc15e20309f..281067fe55c 100644
    --- a/src/hotspot/share/runtime/objectMonitor.hpp
    +++ b/src/hotspot/share/runtime/objectMonitor.hpp
    @@ -121,11 +121,7 @@ class ObjectWaiter : public StackObj {
     //     intptr_t. There's no reason to use a 64-bit type for this field
     //     in a 64-bit JVM.
     
    -#ifndef OM_CACHE_LINE_SIZE
    -// Use DEFAULT_CACHE_LINE_SIZE if not already specified for
    -// the current build platform.
     #define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE
    -#endif
     
     class ObjectMonitor : public CHeapObj {
       friend class ObjectSynchronizer;
    @@ -357,7 +353,6 @@ class ObjectMonitor : public CHeapObj {
       void      ReenterI(JavaThread* current, ObjectWaiter* current_node);
       void      UnlinkAfterAcquire(JavaThread* current, ObjectWaiter* current_node);
       int       TryLock(JavaThread* current);
    -  int       NotRunnable(JavaThread* current, JavaThread* Owner);
       int       TrySpin(JavaThread* current);
       void      ExitEpilog(JavaThread* current, ObjectWaiter* Wakee);
     
    diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp
    index 0eb4015a246..dad10a7b9b4 100644
    --- a/src/hotspot/share/runtime/os.cpp
    +++ b/src/hotspot/share/runtime/os.cpp
    @@ -1105,10 +1105,11 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) {
       st->cr();
     }
     
    +static constexpr int secs_per_day  = 86400;
    +static constexpr int secs_per_hour = 3600;
    +static constexpr int secs_per_min  = 60;
    +
     void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
    -  const int secs_per_day  = 86400;
    -  const int secs_per_hour = 3600;
    -  const int secs_per_min  = 60;
     
       time_t tloc;
       (void)time(&tloc);
    @@ -1134,9 +1135,15 @@ void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
       }
     
       double t = os::elapsedTime();
    +  st->print(" elapsed time: ");
    +  print_elapsed_time(st, t);
    +  st->cr();
    +}
    +
    +void os::print_elapsed_time(outputStream* st, double time) {
       // NOTE: a crash using printf("%f",...) on Linux was historically noted here.
    -  int eltime = (int)t;  // elapsed time in seconds
    -  int eltimeFraction = (int) ((t - eltime) * 1000000);
    +  int eltime = (int)time;  // elapsed time in seconds
    +  int eltimeFraction = (int) ((time - eltime) * 1000000);
     
       // print elapsed time in a human-readable format:
       int eldays = eltime / secs_per_day;
    @@ -1146,7 +1153,7 @@ void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
       int elmins = (eltime - day_secs - hour_secs) / secs_per_min;
       int minute_secs = elmins * secs_per_min;
       int elsecs = (eltime - day_secs - hour_secs - minute_secs);
    -  st->print_cr(" elapsed time: %d.%06d seconds (%dd %dh %dm %ds)", eltime, eltimeFraction, eldays, elhours, elmins, elsecs);
    +  st->print("%d.%06d seconds (%dd %dh %dm %ds)", eltime, eltimeFraction, eldays, elhours, elmins, elsecs);
     }
     
     
    diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp
    index 094fd2509a0..f5346c92307 100644
    --- a/src/hotspot/share/runtime/os.hpp
    +++ b/src/hotspot/share/runtime/os.hpp
    @@ -531,7 +531,6 @@ class os: AllStatic {
       static void   large_page_init();
       static size_t large_page_size();
       static bool   can_commit_large_page_memory();
    -  static bool   can_execute_large_page_memory();
     
       // Check if pointer points to readable memory (by 4-byte read access)
       static bool    is_readable_pointer(const void* p);
    @@ -790,6 +789,7 @@ class os: AllStatic {
       static void print_siginfo(outputStream* st, const void* siginfo);
       static void print_signal_handlers(outputStream* st, char* buf, size_t buflen);
       static void print_date_and_time(outputStream* st, char* buf, size_t buflen);
    +  static void print_elapsed_time(outputStream* st, double time);
     
       static void print_user_info(outputStream* st);
       static void print_active_locale(outputStream* st);
    diff --git a/src/hotspot/share/runtime/prefetch.hpp b/src/hotspot/share/runtime/prefetch.hpp
    index d949899813c..601337c14af 100644
    --- a/src/hotspot/share/runtime/prefetch.hpp
    +++ b/src/hotspot/share/runtime/prefetch.hpp
    @@ -35,12 +35,6 @@
     
     class Prefetch : AllStatic {
      public:
    -  enum style {
    -    do_none,  // Do no prefetching
    -    do_read,  // Do read prefetching
    -    do_write  // Do write prefetching
    -  };
    -
       // Prefetch anticipating read; must not fault, semantically a no-op
       static void read(const void* loc, intx interval);
     
    diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp
    index 7d485e01223..5d64aa65bc6 100644
    --- a/src/hotspot/share/runtime/sharedRuntime.cpp
    +++ b/src/hotspot/share/runtime/sharedRuntime.cpp
    @@ -2081,7 +2081,7 @@ void SharedRuntime::check_member_name_argument_is_last_argument(const methodHand
       assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob");
       assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object");
     
    -  int comp_args_on_stack = java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1);
    +  java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1);
     
       for (int i = 0; i < member_arg_pos; i++) {
         VMReg a =    regs_with_member_name[i].first();
    @@ -3470,7 +3470,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) {
           BasicType ret_type = ss.type();
     
           // Now get the compiled-Java arguments layout.
    -      int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed);
    +      SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed);
     
           // Generate the compiled-to-native wrapper code
           nm = SharedRuntime::generate_native_wrapper(&_masm, method, compile_id, sig_bt, regs, ret_type);
    diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp
    index 78e73578f4d..3e71dcc301a 100644
    --- a/src/hotspot/share/runtime/signature.cpp
    +++ b/src/hotspot/share/runtime/signature.cpp
    @@ -180,7 +180,6 @@ void Fingerprinter::compute_fingerprint_and_return_type(bool static_flag) {
       }
     
     #if defined(_LP64) && !defined(ZERO)
    -  _stack_arg_slots = align_up(_stack_arg_slots, 2);
     #ifdef ASSERT
       int dbg_stack_arg_slots = compute_num_stack_arg_slots(_signature, _param_size, static_flag);
       assert(_stack_arg_slots == dbg_stack_arg_slots, "fingerprinter: %d full: %d", _stack_arg_slots, dbg_stack_arg_slots);
    @@ -237,14 +236,17 @@ void Fingerprinter::do_type_calling_convention(BasicType type) {
       case T_BYTE:
       case T_SHORT:
       case T_INT:
    -#if defined(PPC64) || defined(S390)
         if (_int_args < Argument::n_int_register_parameters_j) {
           _int_args++;
         } else {
    +#if defined(PPC64) || defined(S390)
    +      _stack_arg_slots += 1;
    +#else
    +      _stack_arg_slots = align_up(_stack_arg_slots, 2);
           _stack_arg_slots += 1;
    +#endif // defined(PPC64) || defined(S390)
         }
         break;
    -#endif // defined(PPC64) || defined(S390)
       case T_LONG:
       case T_OBJECT:
       case T_ARRAY:
    @@ -252,26 +254,27 @@ void Fingerprinter::do_type_calling_convention(BasicType type) {
         if (_int_args < Argument::n_int_register_parameters_j) {
           _int_args++;
         } else {
    -      PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2));
    -      S390_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2));
    +      _stack_arg_slots = align_up(_stack_arg_slots, 2);
           _stack_arg_slots += 2;
         }
         break;
       case T_FLOAT:
    -#if defined(PPC64) || defined(S390)
         if (_fp_args < Argument::n_float_register_parameters_j) {
           _fp_args++;
         } else {
    +#if defined(PPC64) || defined(S390)
    +      _stack_arg_slots += 1;
    +#else
    +      _stack_arg_slots = align_up(_stack_arg_slots, 2);
           _stack_arg_slots += 1;
    +#endif // defined(PPC64) || defined(S390)
         }
         break;
    -#endif // defined(PPC64) || defined(S390)
       case T_DOUBLE:
         if (_fp_args < Argument::n_float_register_parameters_j) {
           _fp_args++;
         } else {
    -      PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2));
    -      S390_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2));
    +      _stack_arg_slots = align_up(_stack_arg_slots, 2);
           _stack_arg_slots += 2;
         }
         break;
    diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp
    index 3592d390938..ca9f74a04ed 100644
    --- a/src/hotspot/share/runtime/trimNativeHeap.cpp
    +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp
    @@ -71,11 +71,6 @@ class NativeHeapTrimmerThread : public NamedThread {
         return --_suspend_count;
       }
     
    -  bool is_stopped() const {
    -    assert(_lock->is_locked(), "Must be");
    -    return _stop;
    -  }
    -
       bool at_or_nearing_safepoint() const {
         return SafepointSynchronize::is_at_safepoint() ||
                SafepointSynchronize::is_synchronizing();
    @@ -215,13 +210,12 @@ class NativeHeapTrimmerThread : public NamedThread {
       }
     
       void print_state(outputStream* st) const {
    -    // Don't pull lock during error reporting
    -    Mutex* const lock = VMError::is_error_reported() ? nullptr : _lock;
         int64_t num_trims = 0;
         bool stopped = false;
         uint16_t suspenders = 0;
         {
    -      MutexLocker ml(lock, Mutex::_no_safepoint_check_flag);
    +      // Don't pull lock during error reporting
    +      ConditionalMutexLocker ml(_lock, !VMError::is_error_reported(), Mutex::_no_safepoint_check_flag);
           num_trims = _num_trims_performed;
           stopped = _stop;
           suspenders = _suspend_count;
    diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp
    index 7afd9aaf1b4..19719cb4771 100644
    --- a/src/hotspot/share/services/diagnosticCommand.cpp
    +++ b/src/hotspot/share/services/diagnosticCommand.cpp
    @@ -851,8 +851,15 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
     }
     
     #ifdef LINUX
    +PerfMapDCmd::PerfMapDCmd(outputStream* output, bool heap) :
    +             DCmdWithParser(output, heap),
    +  _filename("filename", "Name of the map file", "STRING", false)
    +{
    +  _dcmdparser.add_dcmd_argument(&_filename);
    +}
    +
     void PerfMapDCmd::execute(DCmdSource source, TRAPS) {
    -  CodeCache::write_perf_map();
    +  CodeCache::write_perf_map(_filename.value());
     }
     #endif // LINUX
     
    diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp
    index a0a34697aee..de6b0c685f9 100644
    --- a/src/hotspot/share/services/diagnosticCommand.hpp
    +++ b/src/hotspot/share/services/diagnosticCommand.hpp
    @@ -602,9 +602,12 @@ class CompileQueueDCmd : public DCmd {
     };
     
     #ifdef LINUX
    -class PerfMapDCmd : public DCmd {
    +class PerfMapDCmd : public DCmdWithParser {
    +protected:
    +  DCmdArgument _filename;
     public:
    -  PerfMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
    +  static int num_arguments() { return 1; }
    +  PerfMapDCmd(outputStream* output, bool heap);
       static const char* name() {
         return "Compiler.perfmap";
       }
    diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp
    index 148f1dca72f..a16665681bb 100644
    --- a/src/hotspot/share/services/heapDumper.cpp
    +++ b/src/hotspot/share/services/heapDumper.cpp
    @@ -1974,6 +1974,25 @@ void SymbolTableDumper::do_symbol(Symbol** p) {
       }
     }
     
    +// Support class used to generate HPROF_GC_CLASS_DUMP records
    +
    +class ClassDumper : public KlassClosure {
    + private:
    +  AbstractDumpWriter* _writer;
    +  AbstractDumpWriter* writer() const { return _writer; }
    +
    + public:
    +  ClassDumper(AbstractDumpWriter* writer) : _writer(writer) {}
    +
    +  void do_klass(Klass* k) {
    +    if (k->is_instance_klass()) {
    +      DumperSupport::dump_instance_class(writer(), k);
    +    } else {
    +      DumperSupport::dump_array_class(writer(), k);
    +    }
    +  }
    +};
    +
     // Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records
     
     class JNILocalsDumper : public OopClosure {
    @@ -2123,6 +2142,19 @@ class ThreadDumper : public CHeapObj {
             && java_lang_VirtualThread::state(vt) != java_lang_VirtualThread::TERMINATED;
       }
     
    +  static bool is_vthread_mounted(oop vt) {
    +    // The code should be consistent with the "mounted virtual thread" case
    +    // (VM_HeapDumper::dump_stack_traces(), ThreadDumper::get_top_frame()).
    +    // I.e. virtual thread is mounted if its carrierThread is not null
    +    // and is_vthread_mounted() for the carrier thread returns true.
    +    oop carrier_thread = java_lang_VirtualThread::carrier_thread(vt);
    +    if (carrier_thread == nullptr) {
    +      return false;
    +    }
    +    JavaThread* java_thread = java_lang_Thread::thread(carrier_thread);
    +    return java_thread->is_vthread_mounted();
    +  }
    +
       ThreadDumper(ThreadType thread_type, JavaThread* java_thread, oop thread_oop);
     
       // affects frame_count
    @@ -2361,21 +2393,25 @@ vframe* ThreadDumper::get_top_frame() const {
       return nullptr;
     }
     
    +// Callback to dump thread-related data for unmounted virtual threads;
    +// implemented by VM_HeapDumper.
    +class UnmountedVThreadDumper {
    + public:
    +  virtual void dump_vthread(oop vt, AbstractDumpWriter* segment_writer) = 0;
    +};
     
    -class VM_HeapDumper;
    -
    -// Support class using when iterating over the heap.
    +// Support class used when iterating over the heap.
     class HeapObjectDumper : public ObjectClosure {
      private:
       AbstractDumpWriter* _writer;
       AbstractDumpWriter* writer()                  { return _writer; }
    +  UnmountedVThreadDumper* _vthread_dumper;
     
       DumperClassCacheTable _class_cache;
     
      public:
    -  HeapObjectDumper(AbstractDumpWriter* writer) {
    -    _writer = writer;
    -  }
    +  HeapObjectDumper(AbstractDumpWriter* writer, UnmountedVThreadDumper* vthread_dumper)
    +    : _writer(writer), _vthread_dumper(vthread_dumper) {}
     
       // called for each object in the heap
       void do_object(oop o);
    @@ -2396,6 +2432,12 @@ void HeapObjectDumper::do_object(oop o) {
       if (o->is_instance()) {
         // create a HPROF_GC_INSTANCE record for each object
         DumperSupport::dump_instance(writer(), o, &_class_cache);
    +    // If we encounter an unmounted virtual thread it needs to be dumped explicitly
    +    // (mounted virtual threads are dumped with their carriers).
    +    if (java_lang_VirtualThread::is_instance(o)
    +        && ThreadDumper::should_dump_vthread(o) && !ThreadDumper::is_vthread_mounted(o)) {
    +      _vthread_dumper->dump_vthread(o, writer());
    +    }
       } else if (o->is_objArray()) {
         // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array
         DumperSupport::dump_object_array(writer(), objArrayOop(o));
    @@ -2411,16 +2453,52 @@ void HeapObjectDumper::do_object(oop o) {
     class DumperController : public CHeapObj {
      private:
        Monitor* _lock;
    +   Mutex* _global_writer_lock;
    +
        const uint   _dumper_number;
        uint   _complete_number;
     
    +   bool   _started; // VM dumper started and acquired global writer lock
    +
      public:
        DumperController(uint number) :
    -     _lock(new (std::nothrow) PaddedMonitor(Mutex::safepoint, "DumperController_lock")),
    +     // _lock and _global_writer_lock are used for synchronization between GC worker threads inside safepoint,
    +     // so we lock with _no_safepoint_check_flag.
    +     // signal_start() acquires _lock when global writer is locked,
    +     // its rank must be less than _global_writer_lock rank.
    +     _lock(new (std::nothrow) PaddedMonitor(Mutex::nosafepoint - 1, "DumperController_lock")),
    +     _global_writer_lock(new (std::nothrow) Mutex(Mutex::nosafepoint, "DumpWriter_lock")),
          _dumper_number(number),
    -     _complete_number(0) { }
    +     _complete_number(0),
    +     _started(false)
    +   {}
    +
    +   ~DumperController() {
    +     delete _lock;
    +     delete _global_writer_lock;
    +   }
     
    -   ~DumperController() { delete _lock; }
    +   // parallel (non VM) dumpers must wait until VM dumper acquires global writer lock
    +   void wait_for_start_signal() {
    +     MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
    +     while (_started == false) {
    +       ml.wait();
    +     }
    +   }
    +
    +   void signal_start() {
    +     MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
    +     _started = true;
    +     ml.notify_all();
    +   }
    +
    +   void lock_global_writer() {
    +     _global_writer_lock->lock_without_safepoint_check();
    +   }
    +
    +   void unlock_global_writer() {
    +     _global_writer_lock->unlock();
    +   }
     
        void dumper_complete(DumpWriter* local_writer, DumpWriter* global_writer) {
          MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
    @@ -2450,7 +2528,7 @@ class DumpMerger : public StackObj {
       int _dump_seq;
     
     private:
    -  void merge_file(char* path);
    +  void merge_file(const char* path);
       void merge_done();
       void set_error(const char* msg);
     
    @@ -2463,8 +2541,28 @@ class DumpMerger : public StackObj {
         _dump_seq(dump_seq) {}
     
       void do_merge();
    +
    +  // returns path for the parallel DumpWriter (resource allocated)
    +  static char* get_writer_path(const char* base_path, int seq);
    +
     };
     
    +char* DumpMerger::get_writer_path(const char* base_path, int seq) {
    +  // approximate required buffer size
    +  size_t buf_size = strlen(base_path)
    +                    + 2                 // ".p"
    +                    + 10                // number (that's enough for 2^32 parallel dumpers)
    +                    + 1;                // '\0'
    +
    +  char* path = NEW_RESOURCE_ARRAY(char, buf_size);
    +  memset(path, 0, buf_size);
    +
    +  os::snprintf(path, buf_size, "%s.p%d", base_path, seq);
    +
    +  return path;
    +}
    +
    +
     void DumpMerger::merge_done() {
       // Writes the HPROF_HEAP_DUMP_END record.
       if (!_has_error) {
    @@ -2487,8 +2585,7 @@ void DumpMerger::set_error(const char* msg) {
     // Merge segmented heap files via sendfile, it's more efficient than the
     // read+write combination, which would require transferring data to and from
     // user space.
    -void DumpMerger::merge_file(char* path) {
    -  assert(!SafepointSynchronize::is_at_safepoint(), "merging happens outside safepoint");
    +void DumpMerger::merge_file(const char* path) {
       TraceTime timer("Merge segmented heap file directly", TRACETIME_LOG(Info, heapdump));
     
       int segment_fd = os::open(path, O_RDONLY, 0);
    @@ -2525,8 +2622,7 @@ void DumpMerger::merge_file(char* path) {
     }
     #else
     // Generic implementation using read+write
    -void DumpMerger::merge_file(char* path) {
    -  assert(!SafepointSynchronize::is_at_safepoint(), "merging happens outside safepoint");
    +void DumpMerger::merge_file(const char* path) {
       TraceTime timer("Merge segmented heap file", TRACETIME_LOG(Info, heapdump));
     
       fileStream segment_fs(path, "rb");
    @@ -2551,7 +2647,6 @@ void DumpMerger::merge_file(char* path) {
     #endif
     
     void DumpMerger::do_merge() {
    -  assert(!SafepointSynchronize::is_at_safepoint(), "merging happens outside safepoint");
       TraceTime timer("Merge heap files complete", TRACETIME_LOG(Info, heapdump));
     
       // Since contents in segmented heap file were already zipped, we don't need to zip
    @@ -2561,10 +2656,9 @@ void DumpMerger::do_merge() {
     
       // Merge the content of the remaining files into base file. Regardless of whether
       // the merge process is successful or not, these segmented files will be deleted.
    -  char path[JVM_MAXPATHLEN];
       for (int i = 0; i < _dump_seq; i++) {
    -    memset(path, 0, JVM_MAXPATHLEN);
    -    os::snprintf(path, JVM_MAXPATHLEN, "%s.p%d", _path, i);
    +    ResourceMark rm;
    +    const char* path = get_writer_path(_path, i);
         if (!_has_error) {
           merge_file(path);
         }
    @@ -2594,7 +2688,7 @@ class VM_HeapDumpMerge : public VM_Operation {
     };
     
     // The VM operation that performs the heap dump
    -class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
    +class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public UnmountedVThreadDumper {
      private:
       static VM_HeapDumper*   _global_dumper;
       static DumpWriter*      _global_writer;
    @@ -2618,10 +2712,15 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
       uint                    _num_dumper_threads;
       DumperController*       _dumper_controller;
       ParallelObjectIterator* _poi;
    -  // worker id of VMDumper thread.
    -  static const size_t VMDumperWorkerId = 0;
    +
    +  // Dumper id of VMDumper thread.
    +  static const int VMDumperId = 0;
       // VM dumper dumps both heap and non-heap data, other dumpers dump heap-only data.
    -  static bool is_vm_dumper(uint worker_id) { return worker_id == VMDumperWorkerId; }
    +  static bool is_vm_dumper(int dumper_id) { return dumper_id == VMDumperId; }
    +  // the 1st dumper calling get_next_dumper_id becomes VM dumper
    +  int get_next_dumper_id() {
    +    return Atomic::fetch_then_add(&_dump_seq, 1);
    +  }
     
       // accessors and setters
       static VM_HeapDumper* dumper()         {  assert(_global_dumper != nullptr, "Error"); return _global_dumper; }
    @@ -2640,17 +2739,11 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
     
       bool skip_operation() const;
     
    -  // create dump writer for every parallel dump thread
    -  DumpWriter* create_local_writer();
    -
    -  // writes a HPROF_LOAD_CLASS record
    +  // writes a HPROF_LOAD_CLASS record to global writer
       static void do_load_class(Klass* k);
     
    -  // writes a HPROF_GC_CLASS_DUMP record for the given class
    -  static void do_class_dump(Klass* k);
    -
       // HPROF_GC_ROOT_THREAD_OBJ records for platform and mounted virtual threads
    -  void dump_threads();
    +  void dump_threads(AbstractDumpWriter* writer);
     
       void add_class_serial_number(Klass* k, int serial_num) {
         _klass_map->at_put_grow(serial_num, k);
    @@ -2661,7 +2754,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
       }
     
       // HPROF_TRACE and HPROF_FRAME records for platform and mounted virtual threads
    -  void dump_stack_traces();
    +  void dump_stack_traces(AbstractDumpWriter* writer);
     
      public:
       VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome, uint num_dump_threads) :
    @@ -2679,7 +2772,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
         _thread_serial_num = 1;
         _frame_serial_num = 1;
     
    -    _dump_seq = 0;
    +    _dump_seq = VMDumperId;
         _num_dumper_threads = num_dump_threads;
         _dumper_controller = nullptr;
         _poi = nullptr;
    @@ -2713,7 +2806,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
       }
       int dump_seq()           { return _dump_seq; }
       bool is_parallel_dump()  { return _num_dumper_threads > 1; }
    -  bool can_parallel_dump(WorkerThreads* workers);
    +  void prepare_parallel_dump(WorkerThreads* workers);
     
       InlinedObjects* inlined_objects() { return &_inlined_objects; }
     
    @@ -2721,6 +2814,9 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
       virtual bool doit_prologue();
       void doit();
       void work(uint worker_id);
    +
    +  // UnmountedVThreadDumper implementation
    +  void dump_vthread(oop vt, AbstractDumpWriter* segment_writer);
     };
     
     VM_HeapDumper* VM_HeapDumper::_global_dumper = nullptr;
    @@ -2764,22 +2860,13 @@ void VM_HeapDumper::do_load_class(Klass* k) {
       writer()->write_symbolID(name);
     }
     
    -// writes a HPROF_GC_CLASS_DUMP record for the given class
    -void VM_HeapDumper::do_class_dump(Klass* k) {
    -  if (k->is_instance_klass()) {
    -    DumperSupport::dump_instance_class(writer(), k);
    -  } else {
    -    DumperSupport::dump_array_class(writer(), k);
    -  }
    -}
    -
     // Write a HPROF_GC_ROOT_THREAD_OBJ record for platform/carrier and mounted virtual threads.
     // Then walk the stack so that locals and JNI locals are dumped.
    -void VM_HeapDumper::dump_threads() {
    -    for (int i = 0; i < _thread_dumpers_count; i++) {
    -        _thread_dumpers[i]->dump_thread_obj(writer());
    -        _thread_dumpers[i]->dump_stack_refs(writer());
    -    }
    +void VM_HeapDumper::dump_threads(AbstractDumpWriter* writer) {
    +  for (int i = 0; i < _thread_dumpers_count; i++) {
    +    _thread_dumpers[i]->dump_thread_obj(writer);
    +    _thread_dumpers[i]->dump_stack_refs(writer);
    +  }
     }
     
     bool VM_HeapDumper::doit_prologue() {
    @@ -2793,31 +2880,21 @@ bool VM_HeapDumper::doit_prologue() {
       return VM_GC_Operation::doit_prologue();
     }
     
    -bool VM_HeapDumper::can_parallel_dump(WorkerThreads* workers) {
    -  bool can_parallel = true;
    +void VM_HeapDumper::prepare_parallel_dump(WorkerThreads* workers) {
       uint num_active_workers = workers != nullptr ? workers->active_workers() : 0;
       uint num_requested_dump_threads = _num_dumper_threads;
       // check if we can dump in parallel based on requested and active threads
       if (num_active_workers <= 1 || num_requested_dump_threads <= 1) {
         _num_dumper_threads = 1;
    -    can_parallel = false;
       } else {
    -    // check if we have extra path room to accommodate segmented heap files
    -    const char* base_path = writer()->get_file_path();
    -    assert(base_path != nullptr, "sanity check");
    -    if ((strlen(base_path) + 7/*.p\d\d\d\d\0*/) >= JVM_MAXPATHLEN) {
    -      _num_dumper_threads = 1;
    -      can_parallel = false;
    -    } else {
    -      _num_dumper_threads = clamp(num_requested_dump_threads, 2U, num_active_workers);
    -    }
    +    _num_dumper_threads = clamp(num_requested_dump_threads, 2U, num_active_workers);
       }
    -
    +  _dumper_controller = new (std::nothrow) DumperController(_num_dumper_threads);
    +  bool can_parallel = _num_dumper_threads > 1;
       log_info(heapdump)("Requested dump threads %u, active dump threads %u, "
                          "actual dump threads %u, parallelism %s",
                          num_requested_dump_threads, num_active_workers,
                          _num_dumper_threads, can_parallel ? "true" : "false");
    -  return can_parallel;
     }
     
     // The VM operation that dumps the heap. The dump consists of the following
    @@ -2865,11 +2942,11 @@ void VM_HeapDumper::doit() {
       set_global_writer();
     
       WorkerThreads* workers = ch->safepoint_workers();
    -  if (!can_parallel_dump(workers)) {
    -    work(VMDumperWorkerId);
    +  prepare_parallel_dump(workers);
    +
    +  if (!is_parallel_dump()) {
    +    work(VMDumperId);
       } else {
    -    uint heap_only_dumper_threads = _num_dumper_threads - 1 /* VMDumper thread */;
    -    _dumper_controller = new (std::nothrow) DumperController(heap_only_dumper_threads);
         ParallelObjectIterator poi(_num_dumper_threads);
         _poi = &poi;
         workers->run_task(this, _num_dumper_threads);
    @@ -2881,26 +2958,19 @@ void VM_HeapDumper::doit() {
       clear_global_writer();
     }
     
    -// prepare DumpWriter for every parallel dump thread
    -DumpWriter* VM_HeapDumper::create_local_writer() {
    -  char* path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
    -  memset(path, 0, JVM_MAXPATHLEN);
    -
    -  // generate segmented heap file path
    -  const char* base_path = writer()->get_file_path();
    -  // share global compressor, local DumpWriter is not responsible for its life cycle
    -  AbstractCompressor* compressor = writer()->compressor();
    -  int seq = Atomic::fetch_then_add(&_dump_seq, 1);
    -  os::snprintf(path, JVM_MAXPATHLEN, "%s.p%d", base_path, seq);
    -
    -  // create corresponding writer for that
    -  DumpWriter* local_writer = new DumpWriter(path, writer()->is_overwrite(), compressor);
    -  return local_writer;
    -}
    -
     void VM_HeapDumper::work(uint worker_id) {
       // VM Dumper works on all non-heap data dumping and part of heap iteration.
    -  if (is_vm_dumper(worker_id)) {
    +  int dumper_id = get_next_dumper_id();
    +
    +  if (is_vm_dumper(dumper_id)) {
    +    // lock global writer, it will be unlocked after VM Dumper finishes with non-heap data
    +    _dumper_controller->lock_global_writer();
    +    _dumper_controller->signal_start();
    +  } else {
    +    _dumper_controller->wait_for_start_signal();
    +  }
    +
    +  if (is_vm_dumper(dumper_id)) {
         TraceTime timer("Dump non-objects", TRACETIME_LOG(Info, heapdump));
         // Write the file header - we always use 1.0.2
         const char* header = "JAVA PROFILE 1.0.2";
    @@ -2929,81 +2999,82 @@ void VM_HeapDumper::work(uint worker_id) {
     
         // write HPROF_FRAME and HPROF_TRACE records
         // this must be called after _klass_map is built when iterating the classes above.
    -    dump_stack_traces();
    +    dump_stack_traces(writer());
     
    -    // HPROF_HEAP_DUMP/HPROF_HEAP_DUMP_SEGMENT starts here
    +    // unlock global writer, so parallel dumpers can dump stack traces of unmounted virtual threads
    +    _dumper_controller->unlock_global_writer();
    +  }
     
    -    // Writes HPROF_GC_CLASS_DUMP records
    -    {
    -      LockedClassesDo locked_dump_class(&do_class_dump);
    -      ClassLoaderDataGraph::classes_do(&locked_dump_class);
    -    }
    -
    -    // HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals
    -    dump_threads();
    -
    -    // HPROF_GC_ROOT_JNI_GLOBAL
    -    JNIGlobalsDumper jni_dumper(writer());
    -    JNIHandles::oops_do(&jni_dumper);
    -    // technically not jni roots, but global roots
    -    // for things like preallocated throwable backtraces
    -    Universe::vm_global()->oops_do(&jni_dumper);
    -    // HPROF_GC_ROOT_STICKY_CLASS
    -    // These should be classes in the null class loader data, and not all classes
    -    // if !ClassUnloading
    -    StickyClassDumper class_dumper(writer());
    -    ClassLoaderData::the_null_class_loader_data()->classes_do(&class_dumper);
    -  }
    -
    -  // Heap iteration.
    -  // writes HPROF_GC_INSTANCE_DUMP records.
    -  // After each sub-record is written check_segment_length will be invoked
    -  // to check if the current segment exceeds a threshold. If so, a new
    -  // segment is started.
    -  // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk
    -  // of the heap dump.
    -  if (!is_parallel_dump()) {
    -    assert(is_vm_dumper(worker_id), "must be");
    -    // == Serial dump
    -    ResourceMark rm;
    -    TraceTime timer("Dump heap objects", TRACETIME_LOG(Info, heapdump));
    -    HeapObjectDumper obj_dumper(writer());
    -    Universe::heap()->object_iterate(&obj_dumper);
    -    writer()->finish_dump_segment();
    -    // Writes the HPROF_HEAP_DUMP_END record because merge does not happen in serial dump
    -    DumperSupport::end_of_dump(writer());
    -    inlined_objects()->dump_flat_arrays(writer());
    -    writer()->flush();
    -    inlined_objects()->release();
    -  } else {
    -    // == Parallel dump
    -    ResourceMark rm;
    -    TraceTime timer("Dump heap objects in parallel", TRACETIME_LOG(Info, heapdump));
    -    DumpWriter* local_writer = is_vm_dumper(worker_id) ? writer() : create_local_writer();
    -    if (!local_writer->has_error()) {
    -      HeapObjectDumper obj_dumper(local_writer);
    -      _poi->object_iterate(&obj_dumper, worker_id);
    -      local_writer->finish_dump_segment();
    -      local_writer->flush();
    -    }
    -    if (is_vm_dumper(worker_id)) {
    -      _dumper_controller->wait_all_dumpers_complete();
    +  // HPROF_HEAP_DUMP/HPROF_HEAP_DUMP_SEGMENT starts here
    +
    +  ResourceMark rm;
    +  // share global compressor, local DumpWriter is not responsible for its life cycle
    +  DumpWriter segment_writer(DumpMerger::get_writer_path(writer()->get_file_path(), dumper_id),
    +                            writer()->is_overwrite(), writer()->compressor());
    +  if (!segment_writer.has_error()) {
    +    if (is_vm_dumper(dumper_id)) {
    +      // dump some non-heap subrecords to heap dump segment
    +      TraceTime timer("Dump non-objects (part 2)", TRACETIME_LOG(Info, heapdump));
    +      // Writes HPROF_GC_CLASS_DUMP records
    +      ClassDumper class_dumper(&segment_writer);
    +      ClassLoaderDataGraph::classes_do(&class_dumper);
    +
    +      // HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals
    +      dump_threads(&segment_writer);
    +
    +      // HPROF_GC_ROOT_JNI_GLOBAL
    +      JNIGlobalsDumper jni_dumper(&segment_writer);
    +      JNIHandles::oops_do(&jni_dumper);
    +      // technically not jni roots, but global roots
    +      // for things like preallocated throwable backtraces
    +      Universe::vm_global()->oops_do(&jni_dumper);
    +      // HPROF_GC_ROOT_STICKY_CLASS
    +      // These should be classes in the null class loader data, and not all classes
    +      // if !ClassUnloading
    +      StickyClassDumper stiky_class_dumper(&segment_writer);
    +      ClassLoaderData::the_null_class_loader_data()->classes_do(&stiky_class_dumper);
    +    }
    +
    +    // Heap iteration.
    +    // writes HPROF_GC_INSTANCE_DUMP records.
    +    // After each sub-record is written check_segment_length will be invoked
    +    // to check if the current segment exceeds a threshold. If so, a new
    +    // segment is started.
    +    // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk
    +    // of the heap dump.
    +
    +    TraceTime timer(is_parallel_dump() ? "Dump heap objects in parallel" : "Dump heap objects", TRACETIME_LOG(Info, heapdump));
    +    HeapObjectDumper obj_dumper(&segment_writer, this);
    +    if (!is_parallel_dump()) {
    +      Universe::heap()->object_iterate(&obj_dumper);
         } else {
    -      _dumper_controller->dumper_complete(local_writer, writer());
    -      delete local_writer;
    -      return;
    +      // == Parallel dump
    +      _poi->object_iterate(&obj_dumper, worker_id);
         }
    +
    +    segment_writer.finish_dump_segment();
    +    segment_writer.flush();
    +  }
    +
    +  _dumper_controller->dumper_complete(&segment_writer, writer());
    +
    +  if (is_vm_dumper(dumper_id)) {
    +    _dumper_controller->wait_all_dumpers_complete();
    +
    +    // flush global writer
    +    writer()->flush();
    +
    +    // At this point, all fragments of the heapdump have been written to separate files.
    +    // We need to merge them into a complete heapdump and write HPROF_HEAP_DUMP_END at that time.
       }
    -  // At this point, all fragments of the heapdump have been written to separate files.
    -  // We need to merge them into a complete heapdump and write HPROF_HEAP_DUMP_END at that time.
     }
     
    -void VM_HeapDumper::dump_stack_traces() {
    +void VM_HeapDumper::dump_stack_traces(AbstractDumpWriter* writer) {
       // write a HPROF_TRACE record without any frames to be referenced as object alloc sites
    -  DumperSupport::write_header(writer(), HPROF_TRACE, 3 * sizeof(u4));
    -  writer()->write_u4((u4)STACK_TRACE_ID);
    -  writer()->write_u4(0);                    // thread number
    -  writer()->write_u4(0);                    // frame count
    +  DumperSupport::write_header(writer, HPROF_TRACE, 3 * sizeof(u4));
    +  writer->write_u4((u4)STACK_TRACE_ID);
    +  writer->write_u4(0);                    // thread number
    +  writer->write_u4(0);                    // frame count
     
       // max number if every platform thread is carrier with mounted virtual thread
       _thread_dumpers = NEW_C_HEAP_ARRAY(ThreadDumper*, Threads::number_of_threads() * 2, mtInternal);
    @@ -3027,7 +3098,7 @@ void VM_HeapDumper::dump_stack_traces() {
               add_oom_frame = false;
             }
             thread_dumper->init_serial_nums(&_thread_serial_num, &_frame_serial_num);
    -        thread_dumper->dump_stack_traces(writer(), _klass_map);
    +        thread_dumper->dump_stack_traces(writer, _klass_map);
           }
     
           // platform or carrier thread
    @@ -3037,11 +3108,27 @@ void VM_HeapDumper::dump_stack_traces() {
             thread_dumper->add_oom_frame(_oome_constructor);
           }
           thread_dumper->init_serial_nums(&_thread_serial_num, &_frame_serial_num);
    -      thread_dumper->dump_stack_traces(writer(), _klass_map);
    +      thread_dumper->dump_stack_traces(writer, _klass_map);
         }
       }
     }
     
    +void VM_HeapDumper::dump_vthread(oop vt, AbstractDumpWriter* segment_writer) {
    +  // unmounted vthread has no JavaThread
    +  ThreadDumper thread_dumper(ThreadDumper::ThreadType::UnmountedVirtual, nullptr, vt);
    +  thread_dumper.init_serial_nums(&_thread_serial_num, &_frame_serial_num);
    +
    +  // write HPROF_TRACE/HPROF_FRAME records to global writer
    +  _dumper_controller->lock_global_writer();
    +  thread_dumper.dump_stack_traces(writer(), _klass_map);
    +  _dumper_controller->unlock_global_writer();
    +
    +  // write HPROF_GC_ROOT_THREAD_OBJ/HPROF_GC_ROOT_JAVA_FRAME/HPROF_GC_ROOT_JNI_LOCAL subrecord
    +  // to segment writer
    +  thread_dumper.dump_thread_obj(segment_writer);
    +  thread_dumper.dump_stack_refs(segment_writer);
    +}
    +
     // dump the heap to given path.
     int HeapDumper::dump(const char* path, outputStream* out, int compression, bool overwrite, uint num_dump_threads) {
       assert(path != nullptr && strlen(path) > 0, "path missing");
    @@ -3083,28 +3170,27 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool
       // record any error that the writer may have encountered
       set_error(writer.error());
     
    -  // For serial dump, once VM_HeapDumper completes, the whole heap dump process
    -  // is done, no further phases needed. For parallel dump, the whole heap dump
    -  // process is done in two phases
    +  // Heap dump process is done in two phases
       //
       // Phase 1: Concurrent threads directly write heap data to multiple heap files.
       //          This is done by VM_HeapDumper, which is performed within safepoint.
       //
       // Phase 2: Merge multiple heap files into one complete heap dump file.
       //          This is done by DumpMerger, which is performed outside safepoint
    -  if (dumper.is_parallel_dump()) {
    -    DumpMerger merger(path, &writer, dumper.inlined_objects(), dumper.dump_seq());
    -    Thread* current_thread = Thread::current();
    -    if (current_thread->is_AttachListener_thread()) {
    -      // perform heapdump file merge operation in the current thread prevents us
    -      // from occupying the VM Thread, which in turn affects the occurrence of
    -      // GC and other VM operations.
    -      merger.do_merge();
    -    } else {
    -      // otherwise, performs it by VM thread
    -      VM_HeapDumpMerge op(&merger);
    -      VMThread::execute(&op);
    -    }
    +
    +  DumpMerger merger(path, &writer, dumper.inlined_objects(), dumper.dump_seq());
    +  Thread* current_thread = Thread::current();
    +  if (current_thread->is_AttachListener_thread()) {
    +    // perform heapdump file merge operation in the current thread prevents us
    +    // from occupying the VM Thread, which in turn affects the occurrence of
    +    // GC and other VM operations.
    +    merger.do_merge();
    +  } else {
    +    // otherwise, performs it by VM thread
    +    VM_HeapDumpMerge op(&merger);
    +    VMThread::execute(&op);
    +  }
    +  if (writer.error() != nullptr) {
         set_error(writer.error());
       }
     
    diff --git a/src/hotspot/share/utilities/copy.cpp b/src/hotspot/share/utilities/copy.cpp
    index 9ead75f2ceb..ed779796943 100644
    --- a/src/hotspot/share/utilities/copy.cpp
    +++ b/src/hotspot/share/utilities/copy.cpp
    @@ -243,6 +243,16 @@ void Copy::fill_to_memory_atomic(void* to, size_t size, jubyte value) {
         }
       } else {
         // Not aligned, so no need to be atomic.
    +#ifdef MUSL_LIBC
    +    // This code is used by Unsafe and may hit the next page after truncation of mapped memory.
    +    // Therefore, we use volatile to prevent compilers from replacing the loop by memset which
    +    // may not trigger SIGBUS as needed (observed on Alpine Linux x86_64)
    +    jbyte fill = value;
    +    for (uintptr_t off = 0; off < size; off += sizeof(jbyte)) {
    +      *(volatile jbyte*)(dst + off) = fill;
    +    }
    +#else
         Copy::fill_to_bytes(dst, size, value);
    +#endif
       }
     }
    diff --git a/src/hotspot/share/utilities/globalCounter.hpp b/src/hotspot/share/utilities/globalCounter.hpp
    index 7e971f33ae3..b336ed4a1da 100644
    --- a/src/hotspot/share/utilities/globalCounter.hpp
    +++ b/src/hotspot/share/utilities/globalCounter.hpp
    @@ -46,9 +46,9 @@ class GlobalCounter : public AllStatic {
       // Since do not know what we will end up next to in BSS, we make sure the
       // counter is on a separate cacheline.
       struct PaddedCounter {
    -    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
         volatile uintx _counter;
    -    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile uintx));
    +    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(volatile uintx));
       };
     
       // The global counter
    diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp
    index 00d3cf99590..f9b26f3d70b 100644
    --- a/src/hotspot/share/utilities/globalDefinitions.hpp
    +++ b/src/hotspot/share/utilities/globalDefinitions.hpp
    @@ -602,11 +602,16 @@ const bool support_IRIW_for_not_multiple_copy_atomic_cpu = false;
     const bool support_IRIW_for_not_multiple_copy_atomic_cpu = PPC64_ONLY(true) NOT_PPC64(false);
     #endif
     
    -// The expected size in bytes of a cache line, used to pad data structures.
    +// The expected size in bytes of a cache line.
     #ifndef DEFAULT_CACHE_LINE_SIZE
     #error "Platform should define DEFAULT_CACHE_LINE_SIZE"
     #endif
     
    +// The default padding size for data structures to avoid false sharing.
    +#ifndef DEFAULT_PADDING_SIZE
    +#error "Platform should define DEFAULT_PADDING_SIZE"
    +#endif
    +
     
     //----------------------------------------------------------------------------------------------------
     // Utility macros for compilers
    diff --git a/src/hotspot/share/utilities/nonblockingQueue.hpp b/src/hotspot/share/utilities/nonblockingQueue.hpp
    index 0c62f077190..814132809fa 100644
    --- a/src/hotspot/share/utilities/nonblockingQueue.hpp
    +++ b/src/hotspot/share/utilities/nonblockingQueue.hpp
    @@ -62,7 +62,7 @@ template
     class NonblockingQueue {
       T* volatile _head;
       // Padding of one cache line to avoid false sharing.
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(T*));
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(T*));
       T* volatile _tail;
     
       NONCOPYABLE(NonblockingQueue);
    diff --git a/src/hotspot/share/utilities/utf8.cpp b/src/hotspot/share/utilities/utf8.cpp
    index 66e48d56065..d7798778b2c 100644
    --- a/src/hotspot/share/utilities/utf8.cpp
    +++ b/src/hotspot/share/utilities/utf8.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -341,10 +341,10 @@ bool UTF8::is_legal_utf8(const unsigned char* buffer, int length,
         // For an unsigned char v,
         // (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
         // (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128.
    -    unsigned char res = b0 | b0 - 1 |
    -                        b1 | b1 - 1 |
    -                        b2 | b2 - 1 |
    -                        b3 | b3 - 1;
    +    unsigned char res = b0 | (b0 - 1) |
    +                        b1 | (b1 - 1) |
    +                        b2 | (b2 - 1) |
    +                        b3 | (b3 - 1);
         if (res >= 128) break;
         i += 4;
       }
    diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp
    index d586c6f4eea..d40504d6d20 100644
    --- a/src/hotspot/share/utilities/vmError.cpp
    +++ b/src/hotspot/share/utilities/vmError.cpp
    @@ -27,6 +27,7 @@
     #include "precompiled.hpp"
     #include "cds/metaspaceShared.hpp"
     #include "code/codeCache.hpp"
    +#include "compiler/compilationFailureInfo.hpp"
     #include "compiler/compileBroker.hpp"
     #include "compiler/disassembler.hpp"
     #include "gc/shared/gcConfig.hpp"
    @@ -1053,6 +1054,12 @@ void VMError::report(outputStream* st, bool _verbose) {
         check_failing_cds_access(st, _siginfo);
         st->cr();
     
    +#if defined(COMPILER1) || defined(COMPILER2)
    +  STEP_IF("printing pending compilation failure",
    +          _verbose && _thread != nullptr && _thread->is_Compiler_thread())
    +    CompilationFailureInfo::print_pending_compilation_failure(st);
    +#endif
    +
       STEP_IF("printing registers", _verbose && _context != nullptr)
         // printing registers
         os::print_context(st, _context);
    diff --git a/src/hotspot/share/utilities/waitBarrier_generic.hpp b/src/hotspot/share/utilities/waitBarrier_generic.hpp
    index d3a45b33b82..e980b3022ef 100644
    --- a/src/hotspot/share/utilities/waitBarrier_generic.hpp
    +++ b/src/hotspot/share/utilities/waitBarrier_generic.hpp
    @@ -38,7 +38,7 @@ class GenericWaitBarrier : public CHeapObj {
         // This would insulate from stalls when adjacent cells have returning
         // workers and contend over the cache line for current latency-critical
         // cell.
    -    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
     
         Semaphore _sem;
     
    @@ -81,14 +81,14 @@ class GenericWaitBarrier : public CHeapObj {
       Cell _cells[CELLS_COUNT];
     
       // Trailing padding to protect the last cell.
    -  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0);
     
       volatile int _barrier_tag;
     
       // Trailing padding to insulate the rest of the barrier from adjacent
       // data structures. The leading padding is not needed, as cell padding
       // handles this for us.
    -  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
    +  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, 0);
     
       NONCOPYABLE(GenericWaitBarrier);
     
    diff --git a/src/java.base/linux/native/libsimdsort/avx2-32bit-qsort.hpp b/src/java.base/linux/native/libsimdsort/avx2-32bit-qsort.hpp
    new file mode 100644
    index 00000000000..9310b0098d8
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/avx2-32bit-qsort.hpp
    @@ -0,0 +1,367 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    +
    +#ifndef AVX2_QSORT_32BIT
    +#define AVX2_QSORT_32BIT
    +
    +#include "avx2-emu-funcs.hpp"
    +#include "xss-common-qsort.h"
    +
    +/*
    + * Constants used in sorting 8 elements in a ymm registers. Based on Bitonic
    + * sorting network (see
    + * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg)
    + */
    +
    +// ymm                  7, 6, 5, 4, 3, 2, 1, 0
    +#define NETWORK_32BIT_AVX2_1 4, 5, 6, 7, 0, 1, 2, 3
    +#define NETWORK_32BIT_AVX2_2 0, 1, 2, 3, 4, 5, 6, 7
    +#define NETWORK_32BIT_AVX2_3 5, 4, 7, 6, 1, 0, 3, 2
    +#define NETWORK_32BIT_AVX2_4 3, 2, 1, 0, 7, 6, 5, 4
    +
    +/*
    + * Assumes ymm is random and performs a full sorting network defined in
    + * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
    + */
    +template 
    +X86_SIMD_SORT_INLINE reg_t sort_ymm_32bit(reg_t ymm) {
    +    const typename vtype::opmask_t oxAA = _mm256_set_epi32(
    +        0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0);
    +    const typename vtype::opmask_t oxCC = _mm256_set_epi32(
    +        0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0);
    +    const typename vtype::opmask_t oxF0 = _mm256_set_epi32(
    +        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0, 0);
    +
    +    const typename vtype::ymmi_t rev_index = vtype::seti(NETWORK_32BIT_AVX2_2);
    +    ymm = cmp_merge(
    +        ymm, vtype::template shuffle(ymm), oxAA);
    +    ymm = cmp_merge(
    +        ymm, vtype::permutexvar(vtype::seti(NETWORK_32BIT_AVX2_1), ymm), oxCC);
    +    ymm = cmp_merge(
    +        ymm, vtype::template shuffle(ymm), oxAA);
    +    ymm = cmp_merge(ymm, vtype::permutexvar(rev_index, ymm), oxF0);
    +    ymm = cmp_merge(
    +        ymm, vtype::permutexvar(vtype::seti(NETWORK_32BIT_AVX2_3), ymm), oxCC);
    +    ymm = cmp_merge(
    +        ymm, vtype::template shuffle(ymm), oxAA);
    +    return ymm;
    +}
    +
    +struct avx2_32bit_swizzle_ops;
    +
    +template <>
    +struct avx2_vector {
    +    using type_t = int32_t;
    +    using reg_t = __m256i;
    +    using ymmi_t = __m256i;
    +    using opmask_t = __m256i;
    +    static const uint8_t numlanes = 8;
    +#ifdef XSS_MINIMAL_NETWORK_SORT
    +    static constexpr int network_sort_threshold = numlanes;
    +#else
    +    static constexpr int network_sort_threshold = 256;
    +#endif
    +    static constexpr int partition_unroll_factor = 4;
    +
    +    using swizzle_ops = avx2_32bit_swizzle_ops;
    +
    +    static type_t type_max() { return X86_SIMD_SORT_MAX_INT32; }
    +    static type_t type_min() { return X86_SIMD_SORT_MIN_INT32; }
    +    static reg_t zmm_max() {
    +        return _mm256_set1_epi32(type_max());
    +    }  // TODO: this should broadcast bits as is?
    +    static opmask_t get_partial_loadmask(uint64_t num_to_read) {
    +        auto mask = ((0x1ull << num_to_read) - 0x1ull);
    +        return convert_int_to_avx2_mask(mask);
    +    }
    +    static ymmi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
    +                       int v8) {
    +        return _mm256_set_epi32(v1, v2, v3, v4, v5, v6, v7, v8);
    +    }
    +    static opmask_t kxor_opmask(opmask_t x, opmask_t y) {
    +        return _mm256_xor_si256(x, y);
    +    }
    +    static opmask_t ge(reg_t x, reg_t y) {
    +        opmask_t equal = eq(x, y);
    +        opmask_t greater = _mm256_cmpgt_epi32(x, y);
    +        return _mm256_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(equal),
    +                                                _mm256_castsi256_ps(greater)));
    +    }
    +    static opmask_t gt(reg_t x, reg_t y) { return _mm256_cmpgt_epi32(x, y); }
    +    static opmask_t eq(reg_t x, reg_t y) { return _mm256_cmpeq_epi32(x, y); }
    +    template 
    +    static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
    +                                void const *base) {
    +        return _mm256_mask_i32gather_epi32(src, base, index, mask, scale);
    +    }
    +    template 
    +    static reg_t i64gather(__m256i index, void const *base) {
    +        return _mm256_i32gather_epi32((int const *)base, index, scale);
    +    }
    +    static reg_t loadu(void const *mem) {
    +        return _mm256_loadu_si256((reg_t const *)mem);
    +    }
    +    static reg_t max(reg_t x, reg_t y) { return _mm256_max_epi32(x, y); }
    +    static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
    +        return avx2_emu_mask_compressstoreu32(mem, mask, x);
    +    }
    +    static reg_t maskz_loadu(opmask_t mask, void const *mem) {
    +        return _mm256_maskload_epi32((const int *)mem, mask);
    +    }
    +    static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
    +        reg_t dst = _mm256_maskload_epi32((type_t *)mem, mask);
    +        return mask_mov(x, mask, dst);
    +    }
    +    static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
    +        return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(x),
    +                                                    _mm256_castsi256_ps(y),
    +                                                    _mm256_castsi256_ps(mask)));
    +    }
    +    static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
    +        return _mm256_maskstore_epi32((type_t *)mem, mask, x);
    +    }
    +    static reg_t min(reg_t x, reg_t y) { return _mm256_min_epi32(x, y); }
    +    static reg_t permutexvar(__m256i idx, reg_t ymm) {
    +        return _mm256_permutevar8x32_epi32(ymm, idx);
    +        // return avx2_emu_permutexvar_epi32(idx, ymm);
    +    }
    +    static reg_t permutevar(reg_t ymm, __m256i idx) {
    +        return _mm256_permutevar8x32_epi32(ymm, idx);
    +    }
    +    static reg_t reverse(reg_t ymm) {
    +        const __m256i rev_index = _mm256_set_epi32(NETWORK_32BIT_AVX2_2);
    +        return permutexvar(rev_index, ymm);
    +    }
    +    static type_t reducemax(reg_t v) {
    +        return avx2_emu_reduce_max32(v);
    +    }
    +    static type_t reducemin(reg_t v) {
    +        return avx2_emu_reduce_min32(v);
    +    }
    +    static reg_t set1(type_t v) { return _mm256_set1_epi32(v); }
    +    template 
    +    static reg_t shuffle(reg_t ymm) {
    +        return _mm256_shuffle_epi32(ymm, mask);
    +    }
    +    static void storeu(void *mem, reg_t x) {
    +        _mm256_storeu_si256((__m256i *)mem, x);
    +    }
    +    static reg_t sort_vec(reg_t x) {
    +        return sort_ymm_32bit>(x);
    +    }
    +    static reg_t cast_from(__m256i v) { return v; }
    +    static __m256i cast_to(reg_t v) { return v; }
    +    static int double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                    opmask_t k, reg_t reg) {
    +        return avx2_double_compressstore32(left_addr, right_addr, k,
    +                                                   reg);
    +    }
    +};
    +
    +template <>
    +struct avx2_vector {
    +    using type_t = float;
    +    using reg_t = __m256;
    +    using ymmi_t = __m256i;
    +    using opmask_t = __m256i;
    +    static const uint8_t numlanes = 8;
    +#ifdef XSS_MINIMAL_NETWORK_SORT
    +    static constexpr int network_sort_threshold = numlanes;
    +#else
    +    static constexpr int network_sort_threshold = 256;
    +#endif
    +    static constexpr int partition_unroll_factor = 4;
    +
    +    using swizzle_ops = avx2_32bit_swizzle_ops;
    +
    +    static type_t type_max() { return X86_SIMD_SORT_INFINITYF; }
    +    static type_t type_min() { return -X86_SIMD_SORT_INFINITYF; }
    +    static reg_t zmm_max() { return _mm256_set1_ps(type_max()); }
    +
    +    static ymmi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
    +                       int v8) {
    +        return _mm256_set_epi32(v1, v2, v3, v4, v5, v6, v7, v8);
    +    }
    +
    +    static reg_t maskz_loadu(opmask_t mask, void const *mem) {
    +        return _mm256_maskload_ps((const float *)mem, mask);
    +    }
    +    static opmask_t ge(reg_t x, reg_t y) {
    +        return _mm256_castps_si256(_mm256_cmp_ps(x, y, _CMP_GE_OQ));
    +    }
    +    static opmask_t gt(reg_t x, reg_t y) {
    +        return _mm256_castps_si256(_mm256_cmp_ps(x, y, _CMP_GT_OQ));
    +    }
    +    static opmask_t eq(reg_t x, reg_t y) {
    +        return _mm256_castps_si256(_mm256_cmp_ps(x, y, _CMP_EQ_OQ));
    +    }
    +    static opmask_t get_partial_loadmask(uint64_t num_to_read) {
    +        auto mask = ((0x1ull << num_to_read) - 0x1ull);
    +        return convert_int_to_avx2_mask(mask);
    +    }
    +    static int32_t convert_mask_to_int(opmask_t mask) {
    +        return convert_avx2_mask_to_int(mask);
    +    }
    +    template 
    +    static opmask_t fpclass(reg_t x) {
    +        if constexpr (type == (0x01 | 0x80)) {
    +            return _mm256_castps_si256(_mm256_cmp_ps(x, x, _CMP_UNORD_Q));
    +        } else {
    +            static_assert(type == (0x01 | 0x80), "should not reach here");
    +        }
    +    }
    +    template 
    +    static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
    +                                void const *base) {
    +        return _mm256_mask_i32gather_ps(src, base, index,
    +                                        _mm256_castsi256_ps(mask), scale);
    +        ;
    +    }
    +    template 
    +    static reg_t i64gather(__m256i index, void const *base) {
    +        return _mm256_i32gather_ps((float *)base, index, scale);
    +    }
    +    static reg_t loadu(void const *mem) {
    +        return _mm256_loadu_ps((float const *)mem);
    +    }
    +    static reg_t max(reg_t x, reg_t y) { return _mm256_max_ps(x, y); }
    +    static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
    +        return avx2_emu_mask_compressstoreu32(mem, mask, x);
    +    }
    +    static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
    +        reg_t dst = _mm256_maskload_ps((type_t *)mem, mask);
    +        return mask_mov(x, mask, dst);
    +    }
    +    static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
    +        return _mm256_blendv_ps(x, y, _mm256_castsi256_ps(mask));
    +    }
    +    static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
    +        return _mm256_maskstore_ps((type_t *)mem, mask, x);
    +    }
    +    static reg_t min(reg_t x, reg_t y) { return _mm256_min_ps(x, y); }
    +    static reg_t permutexvar(__m256i idx, reg_t ymm) {
    +        return _mm256_permutevar8x32_ps(ymm, idx);
    +    }
    +    static reg_t permutevar(reg_t ymm, __m256i idx) {
    +        return _mm256_permutevar8x32_ps(ymm, idx);
    +    }
    +    static reg_t reverse(reg_t ymm) {
    +        const __m256i rev_index = _mm256_set_epi32(NETWORK_32BIT_AVX2_2);
    +        return permutexvar(rev_index, ymm);
    +    }
    +    static type_t reducemax(reg_t v) {
    +        return avx2_emu_reduce_max32(v);
    +    }
    +    static type_t reducemin(reg_t v) {
    +        return avx2_emu_reduce_min32(v);
    +    }
    +    static reg_t set1(type_t v) { return _mm256_set1_ps(v); }
    +    template 
    +    static reg_t shuffle(reg_t ymm) {
    +        return _mm256_castsi256_ps(
    +            _mm256_shuffle_epi32(_mm256_castps_si256(ymm), mask));
    +    }
    +    static void storeu(void *mem, reg_t x) {
    +        _mm256_storeu_ps((float *)mem, x);
    +    }
    +    static reg_t sort_vec(reg_t x) {
    +        return sort_ymm_32bit>(x);
    +    }
    +    static reg_t cast_from(__m256i v) { return _mm256_castsi256_ps(v); }
    +    static __m256i cast_to(reg_t v) { return _mm256_castps_si256(v); }
    +    static int double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                    opmask_t k, reg_t reg) {
    +        return avx2_double_compressstore32(left_addr, right_addr, k,
    +                                                   reg);
    +    }
    +};
    +
    +struct avx2_32bit_swizzle_ops {
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t swap_n(
    +        typename vtype::reg_t reg) {
    +        __m256i v = vtype::cast_to(reg);
    +
    +        if constexpr (scale == 2) {
    +            __m256 vf = _mm256_castsi256_ps(v);
    +            vf = _mm256_permute_ps(vf, 0b10110001);
    +            v = _mm256_castps_si256(vf);
    +        } else if constexpr (scale == 4) {
    +            __m256 vf = _mm256_castsi256_ps(v);
    +            vf = _mm256_permute_ps(vf, 0b01001110);
    +            v = _mm256_castps_si256(vf);
    +        } else if constexpr (scale == 8) {
    +            v = _mm256_permute2x128_si256(v, v, 0b00000001);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
    +
    +        return vtype::cast_from(v);
    +    }
    +
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t reverse_n(
    +        typename vtype::reg_t reg) {
    +        __m256i v = vtype::cast_to(reg);
    +
    +        if constexpr (scale == 2) {
    +            return swap_n(reg);
    +        } else if constexpr (scale == 4) {
    +            constexpr uint64_t mask = 0b00011011;
    +            __m256 vf = _mm256_castsi256_ps(v);
    +            vf = _mm256_permute_ps(vf, mask);
    +            v = _mm256_castps_si256(vf);
    +        } else if constexpr (scale == 8) {
    +            return vtype::reverse(reg);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
    +
    +        return vtype::cast_from(v);
    +    }
    +
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t merge_n(
    +        typename vtype::reg_t reg, typename vtype::reg_t other) {
    +        __m256i v1 = vtype::cast_to(reg);
    +        __m256i v2 = vtype::cast_to(other);
    +
    +        if constexpr (scale == 2) {
    +            v1 = _mm256_blend_epi32(v1, v2, 0b01010101);
    +        } else if constexpr (scale == 4) {
    +            v1 = _mm256_blend_epi32(v1, v2, 0b00110011);
    +        } else if constexpr (scale == 8) {
    +            v1 = _mm256_blend_epi32(v1, v2, 0b00001111);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
    +
    +        return vtype::cast_from(v1);
    +    }
    +};
    +
    +#endif  // AVX2_QSORT_32BIT
    diff --git a/src/java.base/linux/native/libsimdsort/avx2-emu-funcs.hpp b/src/java.base/linux/native/libsimdsort/avx2-emu-funcs.hpp
    new file mode 100644
    index 00000000000..611f3f419bd
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/avx2-emu-funcs.hpp
    @@ -0,0 +1,183 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    +
    +#ifndef AVX2_EMU_FUNCS
    +#define AVX2_EMU_FUNCS
    +
    +#include 
    +#include 
    +
    +#include "xss-common-qsort.h"
    +
    +constexpr auto avx2_mask_helper_lut32 = [] {
    +    std::array, 256> lut{};
    +    for (int64_t i = 0; i <= 0xFF; i++) {
    +        std::array entry{};
    +        for (int j = 0; j < 8; j++) {
    +            if (((i >> j) & 1) == 1)
    +                entry[j] = 0xFFFFFFFF;
    +            else
    +                entry[j] = 0;
    +        }
    +        lut[i] = entry;
    +    }
    +    return lut;
    +}();
    +
    +constexpr auto avx2_compressstore_lut32_gen = [] {
    +    std::array, 256>, 2> lutPair{};
    +    auto &permLut = lutPair[0];
    +    auto &leftLut = lutPair[1];
    +    for (int64_t i = 0; i <= 0xFF; i++) {
    +        std::array indices{};
    +        std::array leftEntry = {0, 0, 0, 0, 0, 0, 0, 0};
    +        int right = 7;
    +        int left = 0;
    +        for (int j = 0; j < 8; j++) {
    +            bool ge = (i >> j) & 1;
    +            if (ge) {
    +                indices[right] = j;
    +                right--;
    +            } else {
    +                indices[left] = j;
    +                leftEntry[left] = 0xFFFFFFFF;
    +                left++;
    +            }
    +        }
    +        permLut[i] = indices;
    +        leftLut[i] = leftEntry;
    +    }
    +    return lutPair;
    +}();
    +
    +constexpr auto avx2_compressstore_lut32_perm = avx2_compressstore_lut32_gen[0];
    +constexpr auto avx2_compressstore_lut32_left = avx2_compressstore_lut32_gen[1];
    +
    +
    +X86_SIMD_SORT_INLINE
    +__m256i convert_int_to_avx2_mask(int32_t m) {
    +    return _mm256_loadu_si256(
    +        (const __m256i *)avx2_mask_helper_lut32[m].data());
    +}
    +
    +X86_SIMD_SORT_INLINE
    +int32_t convert_avx2_mask_to_int(__m256i m) {
    +    return _mm256_movemask_ps(_mm256_castsi256_ps(m));
    +}
    +
    +// Emulators for intrinsics missing from AVX2 compared to AVX512
    +template 
    +T avx2_emu_reduce_max32(typename avx2_vector::reg_t x) {
    +    using vtype = avx2_vector;
    +    using reg_t = typename vtype::reg_t;
    +
    +    reg_t inter1 =
    +        vtype::max(x, vtype::template shuffle(x));
    +    reg_t inter2 = vtype::max(
    +        inter1, vtype::template shuffle(inter1));
    +    T arr[vtype::numlanes];
    +    vtype::storeu(arr, inter2);
    +    return std::max(arr[0], arr[7]);
    +}
    +
    +template 
    +T avx2_emu_reduce_min32(typename avx2_vector::reg_t x) {
    +    using vtype = avx2_vector;
    +    using reg_t = typename vtype::reg_t;
    +
    +    reg_t inter1 =
    +        vtype::min(x, vtype::template shuffle(x));
    +    reg_t inter2 = vtype::min(
    +        inter1, vtype::template shuffle(inter1));
    +    T arr[vtype::numlanes];
    +    vtype::storeu(arr, inter2);
    +    return std::min(arr[0], arr[7]);
    +}
    +
    +template 
    +void avx2_emu_mask_compressstoreu32(void *base_addr,
    +                                    typename avx2_vector::opmask_t k,
    +                                    typename avx2_vector::reg_t reg) {
    +    using vtype = avx2_vector;
    +
    +    T *leftStore = (T *)base_addr;
    +
    +    int32_t shortMask = convert_avx2_mask_to_int(k);
    +    const __m256i &perm = _mm256_loadu_si256(
    +        (const __m256i *)avx2_compressstore_lut32_perm[shortMask].data());
    +    const __m256i &left = _mm256_loadu_si256(
    +        (const __m256i *)avx2_compressstore_lut32_left[shortMask].data());
    +
    +    typename vtype::reg_t temp = vtype::permutevar(reg, perm);
    +
    +    vtype::mask_storeu(leftStore, left, temp);
    +}
    +
    +
    +template 
    +int avx2_double_compressstore32(void *left_addr, void *right_addr,
    +                                typename avx2_vector::opmask_t k,
    +                                typename avx2_vector::reg_t reg) {
    +    using vtype = avx2_vector;
    +
    +    T *leftStore = (T *)left_addr;
    +    T *rightStore = (T *)right_addr;
    +
    +    int32_t shortMask = convert_avx2_mask_to_int(k);
    +    const __m256i &perm = _mm256_loadu_si256(
    +        (const __m256i *)avx2_compressstore_lut32_perm[shortMask].data());
    +
    +    typename vtype::reg_t temp = vtype::permutevar(reg, perm);
    +
    +    vtype::storeu(leftStore, temp);
    +    vtype::storeu(rightStore, temp);
    +
    +    return _mm_popcnt_u32(shortMask);
    +}
    +
    +
    +template 
    +typename avx2_vector::reg_t avx2_emu_max(typename avx2_vector::reg_t x,
    +                                            typename avx2_vector::reg_t y) {
    +    using vtype = avx2_vector;
    +    typename vtype::opmask_t nlt = vtype::gt(x, y);
    +    return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(y),
    +                                                _mm256_castsi256_pd(x),
    +                                                _mm256_castsi256_pd(nlt)));
    +}
    +
    +template 
    +typename avx2_vector::reg_t avx2_emu_min(typename avx2_vector::reg_t x,
    +                                            typename avx2_vector::reg_t y) {
    +    using vtype = avx2_vector;
    +    typename vtype::opmask_t nlt = vtype::gt(x, y);
    +    return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(x),
    +                                                _mm256_castsi256_pd(y),
    +                                                _mm256_castsi256_pd(nlt)));
    +}
    +
    +#endif
    diff --git a/src/java.base/linux/native/libsimdsort/avx2-linux-qsort.cpp b/src/java.base/linux/native/libsimdsort/avx2-linux-qsort.cpp
    new file mode 100644
    index 00000000000..628d65077c7
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/avx2-linux-qsort.cpp
    @@ -0,0 +1,66 @@
    +/*
    + * Copyright (c) 2023 Intel Corporation. All rights reserved.
    + * 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 "simdsort-support.hpp"
    +#ifdef __SIMDSORT_SUPPORTED_LINUX
    +
    +#pragma GCC target("avx2")
    +#include "avx2-32bit-qsort.hpp"
    +#include "classfile_constants.h"
    +
    +
    +#define DLL_PUBLIC __attribute__((visibility("default")))
    +#define INSERTION_SORT_THRESHOLD_32BIT 16
    +
    +extern "C" {
    +
    +    DLL_PUBLIC void avx2_sort(void *array, int elem_type, int32_t from_index, int32_t to_index) {
    +        switch(elem_type) {
    +            case JVM_T_INT:
    +                avx2_fast_sort((int32_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
    +                break;
    +            case JVM_T_FLOAT:
    +                avx2_fast_sort((float*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
    +                break;
    +            default:
    +                assert(false, "Unexpected type");
    +        }
    +    }
    +
    +    DLL_PUBLIC void avx2_partition(void *array, int elem_type, int32_t from_index, int32_t to_index, int32_t *pivot_indices, int32_t index_pivot1, int32_t index_pivot2) {
    +        switch(elem_type) {
    +            case JVM_T_INT:
    +                avx2_fast_partition((int32_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +                break;
    +            case JVM_T_FLOAT:
    +                avx2_fast_partition((float*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +                break;
    +            default:
    +                assert(false, "Unexpected type");
    +        }
    +    }
    +
    +}
    +
    +#endif
    \ No newline at end of file
    diff --git a/src/java.base/linux/native/libsimdsort/avx512-32bit-qsort.hpp b/src/java.base/linux/native/libsimdsort/avx512-32bit-qsort.hpp
    index 4fbe9b97450..25ad265d865 100644
    --- a/src/java.base/linux/native/libsimdsort/avx512-32bit-qsort.hpp
    +++ b/src/java.base/linux/native/libsimdsort/avx512-32bit-qsort.hpp
    @@ -28,7 +28,7 @@
     #ifndef AVX512_QSORT_32BIT
     #define AVX512_QSORT_32BIT
     
    -#include "avx512-common-qsort.h"
    +#include "xss-common-qsort.h"
     
     /*
      * Constants used in sorting 16 elements in a ZMM registers. Based on Bitonic
    @@ -43,130 +43,204 @@
     #define NETWORK_32BIT_6 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4
     #define NETWORK_32BIT_7 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8
     
    +template 
    +X86_SIMD_SORT_INLINE reg_t sort_zmm_32bit(reg_t zmm);
    +
    +struct avx512_32bit_swizzle_ops;
    +
     template <>
     struct zmm_vector {
         using type_t = int32_t;
    -    using zmm_t = __m512i;
    -    using ymm_t = __m256i;
    +    using reg_t = __m512i;
    +    using halfreg_t = __m256i;
         using opmask_t = __mmask16;
         static const uint8_t numlanes = 16;
    +#ifdef XSS_MINIMAL_NETWORK_SORT
    +    static constexpr int network_sort_threshold = numlanes;
    +#else
    +    static constexpr int network_sort_threshold = 512;
    +#endif
    +    static constexpr int partition_unroll_factor = 8;
    +
    +    using swizzle_ops = avx512_32bit_swizzle_ops;
     
         static type_t type_max() { return X86_SIMD_SORT_MAX_INT32; }
         static type_t type_min() { return X86_SIMD_SORT_MIN_INT32; }
    -    static zmm_t zmm_max() { return _mm512_set1_epi32(type_max()); }
    +    static reg_t zmm_max() { return _mm512_set1_epi32(type_max()); }
     
         static opmask_t knot_opmask(opmask_t x) { return _mm512_knot(x); }
    -    static opmask_t ge(zmm_t x, zmm_t y) {
    +
    +    static opmask_t ge(reg_t x, reg_t y) {
             return _mm512_cmp_epi32_mask(x, y, _MM_CMPINT_NLT);
         }
    -    static opmask_t gt(zmm_t x, zmm_t y) {
    +
    +    static opmask_t gt(reg_t x, reg_t y) {
             return _mm512_cmp_epi32_mask(x, y, _MM_CMPINT_GT);
         }
    +
    +    static opmask_t get_partial_loadmask(uint64_t num_to_read) {
    +        return ((0x1ull << num_to_read) - 0x1ull);
    +    }
         template 
    -    static ymm_t i64gather(__m512i index, void const *base) {
    +    static halfreg_t i64gather(__m512i index, void const *base) {
             return _mm512_i64gather_epi32(index, base, scale);
         }
    -    static zmm_t merge(ymm_t y1, ymm_t y2) {
    -        zmm_t z1 = _mm512_castsi256_si512(y1);
    +    static reg_t merge(halfreg_t y1, halfreg_t y2) {
    +        reg_t z1 = _mm512_castsi256_si512(y1);
             return _mm512_inserti32x8(z1, y2, 1);
         }
    -    static zmm_t loadu(void const *mem) { return _mm512_loadu_si512(mem); }
    -    static void mask_compressstoreu(void *mem, opmask_t mask, zmm_t x) {
    +    static reg_t loadu(void const *mem) { return _mm512_loadu_si512(mem); }
    +    static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
             return _mm512_mask_compressstoreu_epi32(mem, mask, x);
         }
    -    static zmm_t mask_loadu(zmm_t x, opmask_t mask, void const *mem) {
    +    static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
             return _mm512_mask_loadu_epi32(x, mask, mem);
         }
    -    static zmm_t mask_mov(zmm_t x, opmask_t mask, zmm_t y) {
    +    static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
             return _mm512_mask_mov_epi32(x, mask, y);
         }
    -    static void mask_storeu(void *mem, opmask_t mask, zmm_t x) {
    +    static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
             return _mm512_mask_storeu_epi32(mem, mask, x);
         }
    -    static zmm_t min(zmm_t x, zmm_t y) { return _mm512_min_epi32(x, y); }
    -    static zmm_t max(zmm_t x, zmm_t y) { return _mm512_max_epi32(x, y); }
    -    static zmm_t permutexvar(__m512i idx, zmm_t zmm) {
    +    static reg_t min(reg_t x, reg_t y) { return _mm512_min_epi32(x, y); }
    +    static reg_t max(reg_t x, reg_t y) { return _mm512_max_epi32(x, y); }
    +    static reg_t permutexvar(__m512i idx, reg_t zmm) {
             return _mm512_permutexvar_epi32(idx, zmm);
         }
    -    static type_t reducemax(zmm_t v) { return _mm512_reduce_max_epi32(v); }
    -    static type_t reducemin(zmm_t v) { return _mm512_reduce_min_epi32(v); }
    -    static zmm_t set1(type_t v) { return _mm512_set1_epi32(v); }
    +    static type_t reducemax(reg_t v) { return _mm512_reduce_max_epi32(v); }
    +    static type_t reducemin(reg_t v) { return _mm512_reduce_min_epi32(v); }
    +    static reg_t set1(type_t v) { return _mm512_set1_epi32(v); }
         template 
    -    static zmm_t shuffle(zmm_t zmm) {
    +    static reg_t shuffle(reg_t zmm) {
             return _mm512_shuffle_epi32(zmm, (_MM_PERM_ENUM)mask);
         }
    -    static void storeu(void *mem, zmm_t x) {
    +    static void storeu(void *mem, reg_t x) {
             return _mm512_storeu_si512(mem, x);
         }
     
    -    static ymm_t max(ymm_t x, ymm_t y) { return _mm256_max_epi32(x, y); }
    -    static ymm_t min(ymm_t x, ymm_t y) { return _mm256_min_epi32(x, y); }
    +    static halfreg_t max(halfreg_t x, halfreg_t y) {
    +        return _mm256_max_epi32(x, y);
    +    }
    +    static halfreg_t min(halfreg_t x, halfreg_t y) {
    +        return _mm256_min_epi32(x, y);
    +    }
    +    static reg_t reverse(reg_t zmm) {
    +        const auto rev_index = _mm512_set_epi32(NETWORK_32BIT_5);
    +        return permutexvar(rev_index, zmm);
    +    }
    +    static reg_t sort_vec(reg_t x) {
    +        return sort_zmm_32bit>(x);
    +    }
    +    static reg_t cast_from(__m512i v) { return v; }
    +    static __m512i cast_to(reg_t v) { return v; }
    +    static int double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                    opmask_t k, reg_t reg) {
    +        return avx512_double_compressstore>(
    +            left_addr, right_addr, k, reg);
    +    }
     };
     template <>
     struct zmm_vector {
         using type_t = float;
    -    using zmm_t = __m512;
    -    using ymm_t = __m256;
    +    using reg_t = __m512;
    +    using halfreg_t = __m256;
         using opmask_t = __mmask16;
         static const uint8_t numlanes = 16;
    +#ifdef XSS_MINIMAL_NETWORK_SORT
    +    static constexpr int network_sort_threshold = numlanes;
    +#else
    +    static constexpr int network_sort_threshold = 512;
    +#endif
    +    static constexpr int partition_unroll_factor = 8;
    +
    +    using swizzle_ops = avx512_32bit_swizzle_ops;
     
         static type_t type_max() { return X86_SIMD_SORT_INFINITYF; }
         static type_t type_min() { return -X86_SIMD_SORT_INFINITYF; }
    -    static zmm_t zmm_max() { return _mm512_set1_ps(type_max()); }
    +    static reg_t zmm_max() { return _mm512_set1_ps(type_max()); }
     
         static opmask_t knot_opmask(opmask_t x) { return _mm512_knot(x); }
    -    static opmask_t ge(zmm_t x, zmm_t y) {
    +    static opmask_t ge(reg_t x, reg_t y) {
             return _mm512_cmp_ps_mask(x, y, _CMP_GE_OQ);
         }
    -    static opmask_t gt(zmm_t x, zmm_t y) {
    +    static opmask_t gt(reg_t x, reg_t y) {
             return _mm512_cmp_ps_mask(x, y, _CMP_GT_OQ);
         }
    +    static opmask_t get_partial_loadmask(uint64_t num_to_read) {
    +        return ((0x1ull << num_to_read) - 0x1ull);
    +    }
    +    static int32_t convert_mask_to_int(opmask_t mask) { return mask; }
    +    template 
    +    static opmask_t fpclass(reg_t x) {
    +        return _mm512_fpclass_ps_mask(x, type);
    +    }
         template 
    -    static ymm_t i64gather(__m512i index, void const *base) {
    +    static halfreg_t i64gather(__m512i index, void const *base) {
             return _mm512_i64gather_ps(index, base, scale);
         }
    -    static zmm_t merge(ymm_t y1, ymm_t y2) {
    -        zmm_t z1 = _mm512_castsi512_ps(
    +    static reg_t merge(halfreg_t y1, halfreg_t y2) {
    +        reg_t z1 = _mm512_castsi512_ps(
                 _mm512_castsi256_si512(_mm256_castps_si256(y1)));
             return _mm512_insertf32x8(z1, y2, 1);
         }
    -    static zmm_t loadu(void const *mem) { return _mm512_loadu_ps(mem); }
    -    static zmm_t max(zmm_t x, zmm_t y) { return _mm512_max_ps(x, y); }
    -    static void mask_compressstoreu(void *mem, opmask_t mask, zmm_t x) {
    +    static reg_t loadu(void const *mem) { return _mm512_loadu_ps(mem); }
    +    static reg_t max(reg_t x, reg_t y) { return _mm512_max_ps(x, y); }
    +    static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
             return _mm512_mask_compressstoreu_ps(mem, mask, x);
         }
    -    static zmm_t mask_loadu(zmm_t x, opmask_t mask, void const *mem) {
    +    static reg_t maskz_loadu(opmask_t mask, void const *mem) {
    +        return _mm512_maskz_loadu_ps(mask, mem);
    +    }
    +    static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
             return _mm512_mask_loadu_ps(x, mask, mem);
         }
    -    static zmm_t mask_mov(zmm_t x, opmask_t mask, zmm_t y) {
    +    static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
             return _mm512_mask_mov_ps(x, mask, y);
         }
    -    static void mask_storeu(void *mem, opmask_t mask, zmm_t x) {
    +    static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
             return _mm512_mask_storeu_ps(mem, mask, x);
         }
    -    static zmm_t min(zmm_t x, zmm_t y) { return _mm512_min_ps(x, y); }
    -    static zmm_t permutexvar(__m512i idx, zmm_t zmm) {
    +    static reg_t min(reg_t x, reg_t y) { return _mm512_min_ps(x, y); }
    +    static reg_t permutexvar(__m512i idx, reg_t zmm) {
             return _mm512_permutexvar_ps(idx, zmm);
         }
    -    static type_t reducemax(zmm_t v) { return _mm512_reduce_max_ps(v); }
    -    static type_t reducemin(zmm_t v) { return _mm512_reduce_min_ps(v); }
    -    static zmm_t set1(type_t v) { return _mm512_set1_ps(v); }
    +    static type_t reducemax(reg_t v) { return _mm512_reduce_max_ps(v); }
    +    static type_t reducemin(reg_t v) { return _mm512_reduce_min_ps(v); }
    +    static reg_t set1(type_t v) { return _mm512_set1_ps(v); }
         template 
    -    static zmm_t shuffle(zmm_t zmm) {
    +    static reg_t shuffle(reg_t zmm) {
             return _mm512_shuffle_ps(zmm, zmm, (_MM_PERM_ENUM)mask);
         }
    -    static void storeu(void *mem, zmm_t x) { return _mm512_storeu_ps(mem, x); }
    +    static void storeu(void *mem, reg_t x) { return _mm512_storeu_ps(mem, x); }
     
    -    static ymm_t max(ymm_t x, ymm_t y) { return _mm256_max_ps(x, y); }
    -    static ymm_t min(ymm_t x, ymm_t y) { return _mm256_min_ps(x, y); }
    +    static halfreg_t max(halfreg_t x, halfreg_t y) {
    +        return _mm256_max_ps(x, y);
    +    }
    +    static halfreg_t min(halfreg_t x, halfreg_t y) {
    +        return _mm256_min_ps(x, y);
    +    }
    +    static reg_t reverse(reg_t zmm) {
    +        const auto rev_index = _mm512_set_epi32(NETWORK_32BIT_5);
    +        return permutexvar(rev_index, zmm);
    +    }
    +    static reg_t sort_vec(reg_t x) {
    +        return sort_zmm_32bit>(x);
    +    }
    +    static reg_t cast_from(__m512i v) { return _mm512_castsi512_ps(v); }
    +    static __m512i cast_to(reg_t v) { return _mm512_castps_si512(v); }
    +    static int double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                    opmask_t k, reg_t reg) {
    +        return avx512_double_compressstore>(
    +            left_addr, right_addr, k, reg);
    +    }
     };
     
     /*
      * Assumes zmm is random and performs a full sorting network defined in
      * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
      */
    -template 
    -X86_SIMD_SORT_INLINE zmm_t sort_zmm_32bit(zmm_t zmm) {
    +template 
    +X86_SIMD_SORT_INLINE reg_t sort_zmm_32bit(reg_t zmm) {
         zmm = cmp_merge(
             zmm, vtype::template shuffle(zmm), 0xAAAA);
         zmm = cmp_merge(
    @@ -193,249 +267,71 @@ X86_SIMD_SORT_INLINE zmm_t sort_zmm_32bit(zmm_t zmm) {
         return zmm;
     }
     
    -// Assumes zmm is bitonic and performs a recursive half cleaner
    -template 
    -X86_SIMD_SORT_INLINE zmm_t bitonic_merge_zmm_32bit(zmm_t zmm) {
    -    // 1) half_cleaner[16]: compare 1-9, 2-10, 3-11 etc ..
    -    zmm = cmp_merge(
    -        zmm, vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_7), zmm),
    -        0xFF00);
    -    // 2) half_cleaner[8]: compare 1-5, 2-6, 3-7 etc ..
    -    zmm = cmp_merge(
    -        zmm, vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_6), zmm),
    -        0xF0F0);
    -    // 3) half_cleaner[4]
    -    zmm = cmp_merge(
    -        zmm, vtype::template shuffle(zmm), 0xCCCC);
    -    // 3) half_cleaner[1]
    -    zmm = cmp_merge(
    -        zmm, vtype::template shuffle(zmm), 0xAAAA);
    -    return zmm;
    -}
    +struct avx512_32bit_swizzle_ops {
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t swap_n(
    +        typename vtype::reg_t reg) {
    +        __m512i v = vtype::cast_to(reg);
     
    -// Assumes zmm1 and zmm2 are sorted and performs a recursive half cleaner
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_two_zmm_32bit(zmm_t *zmm1,
    -                                                      zmm_t *zmm2) {
    -    // 1) First step of a merging network: coex of zmm1 and zmm2 reversed
    -    *zmm2 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), *zmm2);
    -    zmm_t zmm3 = vtype::min(*zmm1, *zmm2);
    -    zmm_t zmm4 = vtype::max(*zmm1, *zmm2);
    -    // 2) Recursive half cleaner for each
    -    *zmm1 = bitonic_merge_zmm_32bit(zmm3);
    -    *zmm2 = bitonic_merge_zmm_32bit(zmm4);
    -}
    -
    -// Assumes [zmm0, zmm1] and [zmm2, zmm3] are sorted and performs a recursive
    -// half cleaner
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_four_zmm_32bit(zmm_t *zmm) {
    -    zmm_t zmm2r = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm[2]);
    -    zmm_t zmm3r = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm[3]);
    -    zmm_t zmm_t1 = vtype::min(zmm[0], zmm3r);
    -    zmm_t zmm_t2 = vtype::min(zmm[1], zmm2r);
    -    zmm_t zmm_t3 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5),
    -                                      vtype::max(zmm[1], zmm2r));
    -    zmm_t zmm_t4 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5),
    -                                      vtype::max(zmm[0], zmm3r));
    -    zmm_t zmm0 = vtype::min(zmm_t1, zmm_t2);
    -    zmm_t zmm1 = vtype::max(zmm_t1, zmm_t2);
    -    zmm_t zmm2 = vtype::min(zmm_t3, zmm_t4);
    -    zmm_t zmm3 = vtype::max(zmm_t3, zmm_t4);
    -    zmm[0] = bitonic_merge_zmm_32bit(zmm0);
    -    zmm[1] = bitonic_merge_zmm_32bit(zmm1);
    -    zmm[2] = bitonic_merge_zmm_32bit(zmm2);
    -    zmm[3] = bitonic_merge_zmm_32bit(zmm3);
    -}
    -
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_eight_zmm_32bit(zmm_t *zmm) {
    -    zmm_t zmm4r = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm[4]);
    -    zmm_t zmm5r = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm[5]);
    -    zmm_t zmm6r = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm[6]);
    -    zmm_t zmm7r = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm[7]);
    -    zmm_t zmm_t1 = vtype::min(zmm[0], zmm7r);
    -    zmm_t zmm_t2 = vtype::min(zmm[1], zmm6r);
    -    zmm_t zmm_t3 = vtype::min(zmm[2], zmm5r);
    -    zmm_t zmm_t4 = vtype::min(zmm[3], zmm4r);
    -    zmm_t zmm_t5 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5),
    -                                      vtype::max(zmm[3], zmm4r));
    -    zmm_t zmm_t6 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5),
    -                                      vtype::max(zmm[2], zmm5r));
    -    zmm_t zmm_t7 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5),
    -                                      vtype::max(zmm[1], zmm6r));
    -    zmm_t zmm_t8 = vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5),
    -                                      vtype::max(zmm[0], zmm7r));
    -    COEX(zmm_t1, zmm_t3);
    -    COEX(zmm_t2, zmm_t4);
    -    COEX(zmm_t5, zmm_t7);
    -    COEX(zmm_t6, zmm_t8);
    -    COEX(zmm_t1, zmm_t2);
    -    COEX(zmm_t3, zmm_t4);
    -    COEX(zmm_t5, zmm_t6);
    -    COEX(zmm_t7, zmm_t8);
    -    zmm[0] = bitonic_merge_zmm_32bit(zmm_t1);
    -    zmm[1] = bitonic_merge_zmm_32bit(zmm_t2);
    -    zmm[2] = bitonic_merge_zmm_32bit(zmm_t3);
    -    zmm[3] = bitonic_merge_zmm_32bit(zmm_t4);
    -    zmm[4] = bitonic_merge_zmm_32bit(zmm_t5);
    -    zmm[5] = bitonic_merge_zmm_32bit(zmm_t6);
    -    zmm[6] = bitonic_merge_zmm_32bit(zmm_t7);
    -    zmm[7] = bitonic_merge_zmm_32bit(zmm_t8);
    -}
    -
    -template 
    -X86_SIMD_SORT_INLINE void sort_16_32bit(type_t *arr, int32_t N) {
    -    typename vtype::opmask_t load_mask = (0x0001 << N) - 0x0001;
    -    typename vtype::zmm_t zmm =
    -        vtype::mask_loadu(vtype::zmm_max(), load_mask, arr);
    -    vtype::mask_storeu(arr, load_mask, sort_zmm_32bit(zmm));
    -}
    +        if constexpr (scale == 2) {
    +            v = _mm512_shuffle_epi32(v, (_MM_PERM_ENUM)0b10110001);
    +        } else if constexpr (scale == 4) {
    +            v = _mm512_shuffle_epi32(v, (_MM_PERM_ENUM)0b01001110);
    +        } else if constexpr (scale == 8) {
    +            v = _mm512_shuffle_i64x2(v, v, 0b10110001);
    +        } else if constexpr (scale == 16) {
    +            v = _mm512_shuffle_i64x2(v, v, 0b01001110);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
     
    -template 
    -X86_SIMD_SORT_INLINE void sort_32_32bit(type_t *arr, int32_t N) {
    -    if (N <= 16) {
    -        sort_16_32bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    zmm_t zmm1 = vtype::loadu(arr);
    -    typename vtype::opmask_t load_mask = (0x0001 << (N - 16)) - 0x0001;
    -    zmm_t zmm2 = vtype::mask_loadu(vtype::zmm_max(), load_mask, arr + 16);
    -    zmm1 = sort_zmm_32bit(zmm1);
    -    zmm2 = sort_zmm_32bit(zmm2);
    -    bitonic_merge_two_zmm_32bit(&zmm1, &zmm2);
    -    vtype::storeu(arr, zmm1);
    -    vtype::mask_storeu(arr + 16, load_mask, zmm2);
    -}
    -
    -template 
    -X86_SIMD_SORT_INLINE void sort_64_32bit(type_t *arr, int32_t N) {
    -    if (N <= 32) {
    -        sort_32_32bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    using opmask_t = typename vtype::opmask_t;
    -    zmm_t zmm[4];
    -    zmm[0] = vtype::loadu(arr);
    -    zmm[1] = vtype::loadu(arr + 16);
    -    opmask_t load_mask1 = 0xFFFF, load_mask2 = 0xFFFF;
    -    uint64_t combined_mask = (0x1ull << (N - 32)) - 0x1ull;
    -    load_mask1 &= combined_mask & 0xFFFF;
    -    load_mask2 &= (combined_mask >> 16) & 0xFFFF;
    -    zmm[2] = vtype::mask_loadu(vtype::zmm_max(), load_mask1, arr + 32);
    -    zmm[3] = vtype::mask_loadu(vtype::zmm_max(), load_mask2, arr + 48);
    -    zmm[0] = sort_zmm_32bit(zmm[0]);
    -    zmm[1] = sort_zmm_32bit(zmm[1]);
    -    zmm[2] = sort_zmm_32bit(zmm[2]);
    -    zmm[3] = sort_zmm_32bit(zmm[3]);
    -    bitonic_merge_two_zmm_32bit(&zmm[0], &zmm[1]);
    -    bitonic_merge_two_zmm_32bit(&zmm[2], &zmm[3]);
    -    bitonic_merge_four_zmm_32bit(zmm);
    -    vtype::storeu(arr, zmm[0]);
    -    vtype::storeu(arr + 16, zmm[1]);
    -    vtype::mask_storeu(arr + 32, load_mask1, zmm[2]);
    -    vtype::mask_storeu(arr + 48, load_mask2, zmm[3]);
    -}
    +        return vtype::cast_from(v);
    +    }
     
    -template 
    -X86_SIMD_SORT_INLINE void sort_128_32bit(type_t *arr, int32_t N) {
    -    if (N <= 64) {
    -        sort_64_32bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    using opmask_t = typename vtype::opmask_t;
    -    zmm_t zmm[8];
    -    zmm[0] = vtype::loadu(arr);
    -    zmm[1] = vtype::loadu(arr + 16);
    -    zmm[2] = vtype::loadu(arr + 32);
    -    zmm[3] = vtype::loadu(arr + 48);
    -    zmm[0] = sort_zmm_32bit(zmm[0]);
    -    zmm[1] = sort_zmm_32bit(zmm[1]);
    -    zmm[2] = sort_zmm_32bit(zmm[2]);
    -    zmm[3] = sort_zmm_32bit(zmm[3]);
    -    opmask_t load_mask1 = 0xFFFF, load_mask2 = 0xFFFF;
    -    opmask_t load_mask3 = 0xFFFF, load_mask4 = 0xFFFF;
    -    if (N != 128) {
    -        uint64_t combined_mask = (0x1ull << (N - 64)) - 0x1ull;
    -        load_mask1 &= combined_mask & 0xFFFF;
    -        load_mask2 &= (combined_mask >> 16) & 0xFFFF;
    -        load_mask3 &= (combined_mask >> 32) & 0xFFFF;
    -        load_mask4 &= (combined_mask >> 48) & 0xFFFF;
    -    }
    -    zmm[4] = vtype::mask_loadu(vtype::zmm_max(), load_mask1, arr + 64);
    -    zmm[5] = vtype::mask_loadu(vtype::zmm_max(), load_mask2, arr + 80);
    -    zmm[6] = vtype::mask_loadu(vtype::zmm_max(), load_mask3, arr + 96);
    -    zmm[7] = vtype::mask_loadu(vtype::zmm_max(), load_mask4, arr + 112);
    -    zmm[4] = sort_zmm_32bit(zmm[4]);
    -    zmm[5] = sort_zmm_32bit(zmm[5]);
    -    zmm[6] = sort_zmm_32bit(zmm[6]);
    -    zmm[7] = sort_zmm_32bit(zmm[7]);
    -    bitonic_merge_two_zmm_32bit(&zmm[0], &zmm[1]);
    -    bitonic_merge_two_zmm_32bit(&zmm[2], &zmm[3]);
    -    bitonic_merge_two_zmm_32bit(&zmm[4], &zmm[5]);
    -    bitonic_merge_two_zmm_32bit(&zmm[6], &zmm[7]);
    -    bitonic_merge_four_zmm_32bit(zmm);
    -    bitonic_merge_four_zmm_32bit(zmm + 4);
    -    bitonic_merge_eight_zmm_32bit(zmm);
    -    vtype::storeu(arr, zmm[0]);
    -    vtype::storeu(arr + 16, zmm[1]);
    -    vtype::storeu(arr + 32, zmm[2]);
    -    vtype::storeu(arr + 48, zmm[3]);
    -    vtype::mask_storeu(arr + 64, load_mask1, zmm[4]);
    -    vtype::mask_storeu(arr + 80, load_mask2, zmm[5]);
    -    vtype::mask_storeu(arr + 96, load_mask3, zmm[6]);
    -    vtype::mask_storeu(arr + 112, load_mask4, zmm[7]);
    -}
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t reverse_n(
    +        typename vtype::reg_t reg) {
    +        __m512i v = vtype::cast_to(reg);
     
    +        if constexpr (scale == 2) {
    +            return swap_n(reg);
    +        } else if constexpr (scale == 4) {
    +            __m512i mask = _mm512_set_epi32(12, 13, 14, 15, 8, 9, 10, 11, 4, 5,
    +                                            6, 7, 0, 1, 2, 3);
    +            v = _mm512_permutexvar_epi32(mask, v);
    +        } else if constexpr (scale == 8) {
    +            __m512i mask = _mm512_set_epi32(8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
    +                                            2, 3, 4, 5, 6, 7);
    +            v = _mm512_permutexvar_epi32(mask, v);
    +        } else if constexpr (scale == 16) {
    +            return vtype::reverse(reg);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
     
    -template 
    -static void qsort_32bit_(type_t *arr, int64_t left, int64_t right,
    -                         int64_t max_iters) {
    -    /*
    -     * Resort to std::sort if quicksort isnt making any progress
    -     */
    -    if (max_iters <= 0) {
    -        std::sort(arr + left, arr + right + 1);
    -        return;
    -    }
    -    /*
    -     * Base case: use bitonic networks to sort arrays <= 128
    -     */
    -    if (right + 1 - left <= 128) {
    -        sort_128_32bit(arr + left, (int32_t)(right + 1 - left));
    -        return;
    +        return vtype::cast_from(v);
         }
     
    -    type_t pivot = get_pivot_scalar(arr, left, right);
    -    type_t smallest = vtype::type_max();
    -    type_t biggest = vtype::type_min();
    -    int64_t pivot_index = partition_avx512_unrolled(
    -        arr, left, right + 1, pivot, &smallest, &biggest, false);
    -    if (pivot != smallest)
    -        qsort_32bit_(arr, left, pivot_index - 1, max_iters - 1);
    -    if (pivot != biggest)
    -        qsort_32bit_(arr, pivot_index, right, max_iters - 1);
    -}
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t merge_n(
    +        typename vtype::reg_t reg, typename vtype::reg_t other) {
    +        __m512i v1 = vtype::cast_to(reg);
    +        __m512i v2 = vtype::cast_to(other);
     
    -template <>
    -void inline avx512_qsort(int32_t *arr, int64_t fromIndex, int64_t toIndex) {
    -    int64_t arrsize = toIndex - fromIndex;
    -    if (arrsize > 1) {
    -        qsort_32bit_, int32_t>(arr, fromIndex, toIndex - 1,
    -                                                   2 * (int64_t)log2(arrsize));
    -    }
    -}
    +        if constexpr (scale == 2) {
    +            v1 = _mm512_mask_blend_epi32(0b0101010101010101, v1, v2);
    +        } else if constexpr (scale == 4) {
    +            v1 = _mm512_mask_blend_epi32(0b0011001100110011, v1, v2);
    +        } else if constexpr (scale == 8) {
    +            v1 = _mm512_mask_blend_epi32(0b0000111100001111, v1, v2);
    +        } else if constexpr (scale == 16) {
    +            v1 = _mm512_mask_blend_epi32(0b0000000011111111, v1, v2);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
     
    -template <>
    -void inline avx512_qsort(float *arr, int64_t fromIndex, int64_t toIndex) {
    -    int64_t arrsize = toIndex - fromIndex;
    -    if (arrsize > 1) {
    -        qsort_32bit_, float>(arr, fromIndex, toIndex - 1,
    -                                               2 * (int64_t)log2(arrsize));
    +        return vtype::cast_from(v1);
         }
    -}
    +};
     
     #endif  // AVX512_QSORT_32BIT
    diff --git a/src/java.base/linux/native/libsimdsort/avx512-64bit-common.h b/src/java.base/linux/native/libsimdsort/avx512-64bit-common.h
    deleted file mode 100644
    index 9993cd22e63..00000000000
    --- a/src/java.base/linux/native/libsimdsort/avx512-64bit-common.h
    +++ /dev/null
    @@ -1,212 +0,0 @@
    -/*
    - * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    - *
    - * This code is free software; you can redistribute it and/or modify it
    - * under the terms of the GNU General Public License version 2 only, as
    - * published by the Free Software Foundation.
    - *
    - * This code is distributed in the hope that it will be useful, but WITHOUT
    - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    - * version 2 for more details (a copy is included in the LICENSE file that
    - * accompanied this code).
    - *
    - * You should have received a copy of the GNU General Public License version
    - * 2 along with this work; if not, write to the Free Software Foundation,
    - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    - *
    - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    - * or visit www.oracle.com if you need additional information or have any
    - * questions.
    - *
    - */
    -
    -// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    -
    -#ifndef AVX512_64BIT_COMMON
    -#define AVX512_64BIT_COMMON
    -#include "avx512-common-qsort.h"
    -
    -/*
    - * Constants used in sorting 8 elements in a ZMM registers. Based on Bitonic
    - * sorting network (see
    - * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg)
    - */
    -// ZMM                  7, 6, 5, 4, 3, 2, 1, 0
    -#define NETWORK_64BIT_1 4, 5, 6, 7, 0, 1, 2, 3
    -#define NETWORK_64BIT_2 0, 1, 2, 3, 4, 5, 6, 7
    -#define NETWORK_64BIT_3 5, 4, 7, 6, 1, 0, 3, 2
    -#define NETWORK_64BIT_4 3, 2, 1, 0, 7, 6, 5, 4
    -
    -template <>
    -struct zmm_vector {
    -    using type_t = int64_t;
    -    using zmm_t = __m512i;
    -    using zmmi_t = __m512i;
    -    using ymm_t = __m512i;
    -    using opmask_t = __mmask8;
    -    static const uint8_t numlanes = 8;
    -
    -    static type_t type_max() { return X86_SIMD_SORT_MAX_INT64; }
    -    static type_t type_min() { return X86_SIMD_SORT_MIN_INT64; }
    -    static zmm_t zmm_max() {
    -        return _mm512_set1_epi64(type_max());
    -    }  // TODO: this should broadcast bits as is?
    -
    -    static zmmi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
    -                       int v8) {
    -        return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
    -    }
    -    static opmask_t kxor_opmask(opmask_t x, opmask_t y) {
    -        return _kxor_mask8(x, y);
    -    }
    -    static opmask_t knot_opmask(opmask_t x) { return _knot_mask8(x); }
    -    static opmask_t le(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_LE);
    -    }
    -    static opmask_t ge(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_NLT);
    -    }
    -    static opmask_t gt(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_GT);
    -    }
    -    static opmask_t eq(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_EQ);
    -    }
    -    template 
    -    static zmm_t mask_i64gather(zmm_t src, opmask_t mask, __m512i index,
    -                                void const *base) {
    -        return _mm512_mask_i64gather_epi64(src, mask, index, base, scale);
    -    }
    -    template 
    -    static zmm_t i64gather(__m512i index, void const *base) {
    -        return _mm512_i64gather_epi64(index, base, scale);
    -    }
    -    static zmm_t loadu(void const *mem) { return _mm512_loadu_si512(mem); }
    -    static zmm_t max(zmm_t x, zmm_t y) { return _mm512_max_epi64(x, y); }
    -    static void mask_compressstoreu(void *mem, opmask_t mask, zmm_t x) {
    -        return _mm512_mask_compressstoreu_epi64(mem, mask, x);
    -    }
    -    static zmm_t maskz_loadu(opmask_t mask, void const *mem) {
    -        return _mm512_maskz_loadu_epi64(mask, mem);
    -    }
    -    static zmm_t mask_loadu(zmm_t x, opmask_t mask, void const *mem) {
    -        return _mm512_mask_loadu_epi64(x, mask, mem);
    -    }
    -    static zmm_t mask_mov(zmm_t x, opmask_t mask, zmm_t y) {
    -        return _mm512_mask_mov_epi64(x, mask, y);
    -    }
    -    static void mask_storeu(void *mem, opmask_t mask, zmm_t x) {
    -        return _mm512_mask_storeu_epi64(mem, mask, x);
    -    }
    -    static zmm_t min(zmm_t x, zmm_t y) { return _mm512_min_epi64(x, y); }
    -    static zmm_t permutexvar(__m512i idx, zmm_t zmm) {
    -        return _mm512_permutexvar_epi64(idx, zmm);
    -    }
    -    static type_t reducemax(zmm_t v) { return _mm512_reduce_max_epi64(v); }
    -    static type_t reducemin(zmm_t v) { return _mm512_reduce_min_epi64(v); }
    -    static zmm_t set1(type_t v) { return _mm512_set1_epi64(v); }
    -    template 
    -    static zmm_t shuffle(zmm_t zmm) {
    -        __m512d temp = _mm512_castsi512_pd(zmm);
    -        return _mm512_castpd_si512(
    -            _mm512_shuffle_pd(temp, temp, (_MM_PERM_ENUM)mask));
    -    }
    -    static void storeu(void *mem, zmm_t x) { _mm512_storeu_si512(mem, x); }
    -};
    -template <>
    -struct zmm_vector {
    -    using type_t = double;
    -    using zmm_t = __m512d;
    -    using zmmi_t = __m512i;
    -    using ymm_t = __m512d;
    -    using opmask_t = __mmask8;
    -    static const uint8_t numlanes = 8;
    -
    -    static type_t type_max() { return X86_SIMD_SORT_INFINITY; }
    -    static type_t type_min() { return -X86_SIMD_SORT_INFINITY; }
    -    static zmm_t zmm_max() { return _mm512_set1_pd(type_max()); }
    -
    -    static zmmi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
    -                       int v8) {
    -        return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
    -    }
    -
    -    static zmm_t maskz_loadu(opmask_t mask, void const *mem) {
    -        return _mm512_maskz_loadu_pd(mask, mem);
    -    }
    -    static opmask_t knot_opmask(opmask_t x) { return _knot_mask8(x); }
    -    static opmask_t ge(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_pd_mask(x, y, _CMP_GE_OQ);
    -    }
    -    static opmask_t gt(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_pd_mask(x, y, _CMP_GT_OQ);
    -    }
    -    static opmask_t eq(zmm_t x, zmm_t y) {
    -        return _mm512_cmp_pd_mask(x, y, _CMP_EQ_OQ);
    -    }
    -    template 
    -    static opmask_t fpclass(zmm_t x) {
    -        return _mm512_fpclass_pd_mask(x, type);
    -    }
    -    template 
    -    static zmm_t mask_i64gather(zmm_t src, opmask_t mask, __m512i index,
    -                                void const *base) {
    -        return _mm512_mask_i64gather_pd(src, mask, index, base, scale);
    -    }
    -    template 
    -    static zmm_t i64gather(__m512i index, void const *base) {
    -        return _mm512_i64gather_pd(index, base, scale);
    -    }
    -    static zmm_t loadu(void const *mem) { return _mm512_loadu_pd(mem); }
    -    static zmm_t max(zmm_t x, zmm_t y) { return _mm512_max_pd(x, y); }
    -    static void mask_compressstoreu(void *mem, opmask_t mask, zmm_t x) {
    -        return _mm512_mask_compressstoreu_pd(mem, mask, x);
    -    }
    -    static zmm_t mask_loadu(zmm_t x, opmask_t mask, void const *mem) {
    -        return _mm512_mask_loadu_pd(x, mask, mem);
    -    }
    -    static zmm_t mask_mov(zmm_t x, opmask_t mask, zmm_t y) {
    -        return _mm512_mask_mov_pd(x, mask, y);
    -    }
    -    static void mask_storeu(void *mem, opmask_t mask, zmm_t x) {
    -        return _mm512_mask_storeu_pd(mem, mask, x);
    -    }
    -    static zmm_t min(zmm_t x, zmm_t y) { return _mm512_min_pd(x, y); }
    -    static zmm_t permutexvar(__m512i idx, zmm_t zmm) {
    -        return _mm512_permutexvar_pd(idx, zmm);
    -    }
    -    static type_t reducemax(zmm_t v) { return _mm512_reduce_max_pd(v); }
    -    static type_t reducemin(zmm_t v) { return _mm512_reduce_min_pd(v); }
    -    static zmm_t set1(type_t v) { return _mm512_set1_pd(v); }
    -    template 
    -    static zmm_t shuffle(zmm_t zmm) {
    -        return _mm512_shuffle_pd(zmm, zmm, (_MM_PERM_ENUM)mask);
    -    }
    -    static void storeu(void *mem, zmm_t x) { _mm512_storeu_pd(mem, x); }
    -};
    -
    -/*
    - * Assumes zmm is random and performs a full sorting network defined in
    - * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
    - */
    -template 
    -X86_SIMD_SORT_INLINE zmm_t sort_zmm_64bit(zmm_t zmm) {
    -    const typename vtype::zmmi_t rev_index = vtype::seti(NETWORK_64BIT_2);
    -    zmm = cmp_merge(
    -        zmm, vtype::template shuffle(zmm), 0xAA);
    -    zmm = cmp_merge(
    -        zmm, vtype::permutexvar(vtype::seti(NETWORK_64BIT_1), zmm), 0xCC);
    -    zmm = cmp_merge(
    -        zmm, vtype::template shuffle(zmm), 0xAA);
    -    zmm = cmp_merge(zmm, vtype::permutexvar(rev_index, zmm), 0xF0);
    -    zmm = cmp_merge(
    -        zmm, vtype::permutexvar(vtype::seti(NETWORK_64BIT_3), zmm), 0xCC);
    -    zmm = cmp_merge(
    -        zmm, vtype::template shuffle(zmm), 0xAA);
    -    return zmm;
    -}
    -
    -
    -#endif
    diff --git a/src/java.base/linux/native/libsimdsort/avx512-64bit-qsort.hpp b/src/java.base/linux/native/libsimdsort/avx512-64bit-qsort.hpp
    index e28ebe19695..6c1fba6ebb6 100644
    --- a/src/java.base/linux/native/libsimdsort/avx512-64bit-qsort.hpp
    +++ b/src/java.base/linux/native/libsimdsort/avx512-64bit-qsort.hpp
    @@ -27,746 +27,317 @@
     #ifndef AVX512_QSORT_64BIT
     #define AVX512_QSORT_64BIT
     
    -#include "avx512-64bit-common.h"
    +#include "xss-common-includes.h"
    +#include "xss-common-qsort.h"
     
    -// Assumes zmm is bitonic and performs a recursive half cleaner
    -template 
    -X86_SIMD_SORT_INLINE zmm_t bitonic_merge_zmm_64bit(zmm_t zmm) {
    -    // 1) half_cleaner[8]: compare 0-4, 1-5, 2-6, 3-7
    +/*
    + * Constants used in sorting 8 elements in a ZMM registers. Based on Bitonic
    + * sorting network (see
    + * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg)
    + */
    +// ZMM                  7, 6, 5, 4, 3, 2, 1, 0
    +#define NETWORK_64BIT_1 4, 5, 6, 7, 0, 1, 2, 3
    +#define NETWORK_64BIT_2 0, 1, 2, 3, 4, 5, 6, 7
    +#define NETWORK_64BIT_3 5, 4, 7, 6, 1, 0, 3, 2
    +#define NETWORK_64BIT_4 3, 2, 1, 0, 7, 6, 5, 4
    +
    +template 
    +X86_SIMD_SORT_INLINE reg_t sort_zmm_64bit(reg_t zmm);
    +
    +struct avx512_64bit_swizzle_ops;
    +
    +template <>
    +struct zmm_vector {
    +    using type_t = int64_t;
    +    using reg_t = __m512i;
    +    using regi_t = __m512i;
    +    using halfreg_t = __m512i;
    +    using opmask_t = __mmask8;
    +    static const uint8_t numlanes = 8;
    +#ifdef XSS_MINIMAL_NETWORK_SORT
    +    static constexpr int network_sort_threshold = numlanes;
    +#else
    +    static constexpr int network_sort_threshold = 256;
    +#endif
    +    static constexpr int partition_unroll_factor = 8;
    +
    +    using swizzle_ops = avx512_64bit_swizzle_ops;
    +
    +    static type_t type_max() { return X86_SIMD_SORT_MAX_INT64; }
    +    static type_t type_min() { return X86_SIMD_SORT_MIN_INT64; }
    +    static reg_t zmm_max() {
    +        return _mm512_set1_epi64(type_max());
    +    }  // TODO: this should broadcast bits as is?
    +
    +    static regi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
    +                       int v8) {
    +        return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
    +    }
    +    static reg_t set(type_t v1, type_t v2, type_t v3, type_t v4, type_t v5,
    +                     type_t v6, type_t v7, type_t v8) {
    +        return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
    +    }
    +    static opmask_t kxor_opmask(opmask_t x, opmask_t y) {
    +        return _kxor_mask8(x, y);
    +    }
    +    static opmask_t knot_opmask(opmask_t x) { return _knot_mask8(x); }
    +    static opmask_t le(reg_t x, reg_t y) {
    +        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_LE);
    +    }
    +    static opmask_t ge(reg_t x, reg_t y) {
    +        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_NLT);
    +    }
    +    static opmask_t gt(reg_t x, reg_t y) {
    +        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_GT);
    +    }
    +    static opmask_t get_partial_loadmask(uint64_t num_to_read) {
    +        return ((0x1ull << num_to_read) - 0x1ull);
    +    }
    +    static opmask_t eq(reg_t x, reg_t y) {
    +        return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_EQ);
    +    }
    +    template 
    +    static reg_t mask_i64gather(reg_t src, opmask_t mask, __m512i index,
    +                                void const *base) {
    +        return _mm512_mask_i64gather_epi64(src, mask, index, base, scale);
    +    }
    +    template 
    +    static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
    +                                void const *base) {
    +        return _mm512_mask_i32gather_epi64(src, mask, index, base, scale);
    +    }
    +    static reg_t i64gather(type_t *arr, arrsize_t *ind) {
    +        return set(arr[ind[7]], arr[ind[6]], arr[ind[5]], arr[ind[4]],
    +                   arr[ind[3]], arr[ind[2]], arr[ind[1]], arr[ind[0]]);
    +    }
    +    static reg_t loadu(void const *mem) { return _mm512_loadu_si512(mem); }
    +    static reg_t max(reg_t x, reg_t y) { return _mm512_max_epi64(x, y); }
    +    static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
    +        return _mm512_mask_compressstoreu_epi64(mem, mask, x);
    +    }
    +    static reg_t maskz_loadu(opmask_t mask, void const *mem) {
    +        return _mm512_maskz_loadu_epi64(mask, mem);
    +    }
    +    static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
    +        return _mm512_mask_loadu_epi64(x, mask, mem);
    +    }
    +    static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
    +        return _mm512_mask_mov_epi64(x, mask, y);
    +    }
    +    static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
    +        return _mm512_mask_storeu_epi64(mem, mask, x);
    +    }
    +    static reg_t min(reg_t x, reg_t y) { return _mm512_min_epi64(x, y); }
    +    static reg_t permutexvar(__m512i idx, reg_t zmm) {
    +        return _mm512_permutexvar_epi64(idx, zmm);
    +    }
    +    static type_t reducemax(reg_t v) { return _mm512_reduce_max_epi64(v); }
    +    static type_t reducemin(reg_t v) { return _mm512_reduce_min_epi64(v); }
    +    static reg_t set1(type_t v) { return _mm512_set1_epi64(v); }
    +    template 
    +    static reg_t shuffle(reg_t zmm) {
    +        __m512d temp = _mm512_castsi512_pd(zmm);
    +        return _mm512_castpd_si512(
    +            _mm512_shuffle_pd(temp, temp, (_MM_PERM_ENUM)mask));
    +    }
    +    static void storeu(void *mem, reg_t x) { _mm512_storeu_si512(mem, x); }
    +    static reg_t reverse(reg_t zmm) {
    +        const regi_t rev_index = seti(NETWORK_64BIT_2);
    +        return permutexvar(rev_index, zmm);
    +    }
    +    static reg_t sort_vec(reg_t x) {
    +        return sort_zmm_64bit>(x);
    +    }
    +    static reg_t cast_from(__m512i v) { return v; }
    +    static __m512i cast_to(reg_t v) { return v; }
    +    static int double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                    opmask_t k, reg_t reg) {
    +        return avx512_double_compressstore>(
    +            left_addr, right_addr, k, reg);
    +    }
    +};
    +template <>
    +struct zmm_vector {
    +    using type_t = double;
    +    using reg_t = __m512d;
    +    using regi_t = __m512i;
    +    using halfreg_t = __m512d;
    +    using opmask_t = __mmask8;
    +    static const uint8_t numlanes = 8;
    +#ifdef XSS_MINIMAL_NETWORK_SORT
    +    static constexpr int network_sort_threshold = numlanes;
    +#else
    +    static constexpr int network_sort_threshold = 256;
    +#endif
    +    static constexpr int partition_unroll_factor = 8;
    +
    +    using swizzle_ops = avx512_64bit_swizzle_ops;
    +
    +    static type_t type_max() { return X86_SIMD_SORT_INFINITY; }
    +    static type_t type_min() { return -X86_SIMD_SORT_INFINITY; }
    +    static reg_t zmm_max() { return _mm512_set1_pd(type_max()); }
    +    static regi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
    +                       int v8) {
    +        return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
    +    }
    +    static reg_t set(type_t v1, type_t v2, type_t v3, type_t v4, type_t v5,
    +                     type_t v6, type_t v7, type_t v8) {
    +        return _mm512_set_pd(v1, v2, v3, v4, v5, v6, v7, v8);
    +    }
    +    static reg_t maskz_loadu(opmask_t mask, void const *mem) {
    +        return _mm512_maskz_loadu_pd(mask, mem);
    +    }
    +    static opmask_t knot_opmask(opmask_t x) { return _knot_mask8(x); }
    +    static opmask_t ge(reg_t x, reg_t y) {
    +        return _mm512_cmp_pd_mask(x, y, _CMP_GE_OQ);
    +    }
    +    static opmask_t gt(reg_t x, reg_t y) {
    +        return _mm512_cmp_pd_mask(x, y, _CMP_GT_OQ);
    +    }
    +    static opmask_t eq(reg_t x, reg_t y) {
    +        return _mm512_cmp_pd_mask(x, y, _CMP_EQ_OQ);
    +    }
    +    static opmask_t get_partial_loadmask(uint64_t num_to_read) {
    +        return ((0x1ull << num_to_read) - 0x1ull);
    +    }
    +    static int32_t convert_mask_to_int(opmask_t mask) { return mask; }
    +    template 
    +    static opmask_t fpclass(reg_t x) {
    +        return _mm512_fpclass_pd_mask(x, type);
    +    }
    +    template 
    +    static reg_t mask_i64gather(reg_t src, opmask_t mask, __m512i index,
    +                                void const *base) {
    +        return _mm512_mask_i64gather_pd(src, mask, index, base, scale);
    +    }
    +    template 
    +    static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
    +                                void const *base) {
    +        return _mm512_mask_i32gather_pd(src, mask, index, base, scale);
    +    }
    +    static reg_t i64gather(type_t *arr, arrsize_t *ind) {
    +        return set(arr[ind[7]], arr[ind[6]], arr[ind[5]], arr[ind[4]],
    +                   arr[ind[3]], arr[ind[2]], arr[ind[1]], arr[ind[0]]);
    +    }
    +    static reg_t loadu(void const *mem) { return _mm512_loadu_pd(mem); }
    +    static reg_t max(reg_t x, reg_t y) { return _mm512_max_pd(x, y); }
    +    static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
    +        return _mm512_mask_compressstoreu_pd(mem, mask, x);
    +    }
    +    static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
    +        return _mm512_mask_loadu_pd(x, mask, mem);
    +    }
    +    static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
    +        return _mm512_mask_mov_pd(x, mask, y);
    +    }
    +    static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
    +        return _mm512_mask_storeu_pd(mem, mask, x);
    +    }
    +    static reg_t min(reg_t x, reg_t y) { return _mm512_min_pd(x, y); }
    +    static reg_t permutexvar(__m512i idx, reg_t zmm) {
    +        return _mm512_permutexvar_pd(idx, zmm);
    +    }
    +    static type_t reducemax(reg_t v) { return _mm512_reduce_max_pd(v); }
    +    static type_t reducemin(reg_t v) { return _mm512_reduce_min_pd(v); }
    +    static reg_t set1(type_t v) { return _mm512_set1_pd(v); }
    +    template 
    +    static reg_t shuffle(reg_t zmm) {
    +        return _mm512_shuffle_pd(zmm, zmm, (_MM_PERM_ENUM)mask);
    +    }
    +    static void storeu(void *mem, reg_t x) { _mm512_storeu_pd(mem, x); }
    +    static reg_t reverse(reg_t zmm) {
    +        const regi_t rev_index = seti(NETWORK_64BIT_2);
    +        return permutexvar(rev_index, zmm);
    +    }
    +    static reg_t sort_vec(reg_t x) {
    +        return sort_zmm_64bit>(x);
    +    }
    +    static reg_t cast_from(__m512i v) { return _mm512_castsi512_pd(v); }
    +    static __m512i cast_to(reg_t v) { return _mm512_castpd_si512(v); }
    +    static int double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                    opmask_t k, reg_t reg) {
    +        return avx512_double_compressstore>(
    +            left_addr, right_addr, k, reg);
    +    }
    +};
    +
    +/*
    + * Assumes zmm is random and performs a full sorting network defined in
    + * https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
    + */
    +template 
    +X86_SIMD_SORT_INLINE reg_t sort_zmm_64bit(reg_t zmm) {
    +    const typename vtype::regi_t rev_index = vtype::seti(NETWORK_64BIT_2);
    +    zmm = cmp_merge(
    +        zmm, vtype::template shuffle(zmm), 0xAA);
    +    zmm = cmp_merge(
    +        zmm, vtype::permutexvar(vtype::seti(NETWORK_64BIT_1), zmm), 0xCC);
         zmm = cmp_merge(
    -        zmm, vtype::permutexvar(_mm512_set_epi64(NETWORK_64BIT_4), zmm), 0xF0);
    -    // 2) half_cleaner[4]
    +        zmm, vtype::template shuffle(zmm), 0xAA);
    +    zmm = cmp_merge(zmm, vtype::permutexvar(rev_index, zmm), 0xF0);
         zmm = cmp_merge(
    -        zmm, vtype::permutexvar(_mm512_set_epi64(NETWORK_64BIT_3), zmm), 0xCC);
    -    // 3) half_cleaner[1]
    +        zmm, vtype::permutexvar(vtype::seti(NETWORK_64BIT_3), zmm), 0xCC);
         zmm = cmp_merge(
             zmm, vtype::template shuffle(zmm), 0xAA);
         return zmm;
     }
    -// Assumes zmm1 and zmm2 are sorted and performs a recursive half cleaner
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_two_zmm_64bit(zmm_t &zmm1,
    -                                                      zmm_t &zmm2) {
    -    const __m512i rev_index = _mm512_set_epi64(NETWORK_64BIT_2);
    -    // 1) First step of a merging network: coex of zmm1 and zmm2 reversed
    -    zmm2 = vtype::permutexvar(rev_index, zmm2);
    -    zmm_t zmm3 = vtype::min(zmm1, zmm2);
    -    zmm_t zmm4 = vtype::max(zmm1, zmm2);
    -    // 2) Recursive half cleaner for each
    -    zmm1 = bitonic_merge_zmm_64bit(zmm3);
    -    zmm2 = bitonic_merge_zmm_64bit(zmm4);
    -}
    -// Assumes [zmm0, zmm1] and [zmm2, zmm3] are sorted and performs a recursive
    -// half cleaner
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_four_zmm_64bit(zmm_t *zmm) {
    -    const __m512i rev_index = _mm512_set_epi64(NETWORK_64BIT_2);
    -    // 1) First step of a merging network
    -    zmm_t zmm2r = vtype::permutexvar(rev_index, zmm[2]);
    -    zmm_t zmm3r = vtype::permutexvar(rev_index, zmm[3]);
    -    zmm_t zmm_t1 = vtype::min(zmm[0], zmm3r);
    -    zmm_t zmm_t2 = vtype::min(zmm[1], zmm2r);
    -    // 2) Recursive half clearer: 16
    -    zmm_t zmm_t3 = vtype::permutexvar(rev_index, vtype::max(zmm[1], zmm2r));
    -    zmm_t zmm_t4 = vtype::permutexvar(rev_index, vtype::max(zmm[0], zmm3r));
    -    zmm_t zmm0 = vtype::min(zmm_t1, zmm_t2);
    -    zmm_t zmm1 = vtype::max(zmm_t1, zmm_t2);
    -    zmm_t zmm2 = vtype::min(zmm_t3, zmm_t4);
    -    zmm_t zmm3 = vtype::max(zmm_t3, zmm_t4);
    -    zmm[0] = bitonic_merge_zmm_64bit(zmm0);
    -    zmm[1] = bitonic_merge_zmm_64bit(zmm1);
    -    zmm[2] = bitonic_merge_zmm_64bit(zmm2);
    -    zmm[3] = bitonic_merge_zmm_64bit(zmm3);
    -}
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_eight_zmm_64bit(zmm_t *zmm) {
    -    const __m512i rev_index = _mm512_set_epi64(NETWORK_64BIT_2);
    -    zmm_t zmm4r = vtype::permutexvar(rev_index, zmm[4]);
    -    zmm_t zmm5r = vtype::permutexvar(rev_index, zmm[5]);
    -    zmm_t zmm6r = vtype::permutexvar(rev_index, zmm[6]);
    -    zmm_t zmm7r = vtype::permutexvar(rev_index, zmm[7]);
    -    zmm_t zmm_t1 = vtype::min(zmm[0], zmm7r);
    -    zmm_t zmm_t2 = vtype::min(zmm[1], zmm6r);
    -    zmm_t zmm_t3 = vtype::min(zmm[2], zmm5r);
    -    zmm_t zmm_t4 = vtype::min(zmm[3], zmm4r);
    -    zmm_t zmm_t5 = vtype::permutexvar(rev_index, vtype::max(zmm[3], zmm4r));
    -    zmm_t zmm_t6 = vtype::permutexvar(rev_index, vtype::max(zmm[2], zmm5r));
    -    zmm_t zmm_t7 = vtype::permutexvar(rev_index, vtype::max(zmm[1], zmm6r));
    -    zmm_t zmm_t8 = vtype::permutexvar(rev_index, vtype::max(zmm[0], zmm7r));
    -    COEX(zmm_t1, zmm_t3);
    -    COEX(zmm_t2, zmm_t4);
    -    COEX(zmm_t5, zmm_t7);
    -    COEX(zmm_t6, zmm_t8);
    -    COEX(zmm_t1, zmm_t2);
    -    COEX(zmm_t3, zmm_t4);
    -    COEX(zmm_t5, zmm_t6);
    -    COEX(zmm_t7, zmm_t8);
    -    zmm[0] = bitonic_merge_zmm_64bit(zmm_t1);
    -    zmm[1] = bitonic_merge_zmm_64bit(zmm_t2);
    -    zmm[2] = bitonic_merge_zmm_64bit(zmm_t3);
    -    zmm[3] = bitonic_merge_zmm_64bit(zmm_t4);
    -    zmm[4] = bitonic_merge_zmm_64bit(zmm_t5);
    -    zmm[5] = bitonic_merge_zmm_64bit(zmm_t6);
    -    zmm[6] = bitonic_merge_zmm_64bit(zmm_t7);
    -    zmm[7] = bitonic_merge_zmm_64bit(zmm_t8);
    -}
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_sixteen_zmm_64bit(zmm_t *zmm) {
    -    const __m512i rev_index = _mm512_set_epi64(NETWORK_64BIT_2);
    -    zmm_t zmm8r = vtype::permutexvar(rev_index, zmm[8]);
    -    zmm_t zmm9r = vtype::permutexvar(rev_index, zmm[9]);
    -    zmm_t zmm10r = vtype::permutexvar(rev_index, zmm[10]);
    -    zmm_t zmm11r = vtype::permutexvar(rev_index, zmm[11]);
    -    zmm_t zmm12r = vtype::permutexvar(rev_index, zmm[12]);
    -    zmm_t zmm13r = vtype::permutexvar(rev_index, zmm[13]);
    -    zmm_t zmm14r = vtype::permutexvar(rev_index, zmm[14]);
    -    zmm_t zmm15r = vtype::permutexvar(rev_index, zmm[15]);
    -    zmm_t zmm_t1 = vtype::min(zmm[0], zmm15r);
    -    zmm_t zmm_t2 = vtype::min(zmm[1], zmm14r);
    -    zmm_t zmm_t3 = vtype::min(zmm[2], zmm13r);
    -    zmm_t zmm_t4 = vtype::min(zmm[3], zmm12r);
    -    zmm_t zmm_t5 = vtype::min(zmm[4], zmm11r);
    -    zmm_t zmm_t6 = vtype::min(zmm[5], zmm10r);
    -    zmm_t zmm_t7 = vtype::min(zmm[6], zmm9r);
    -    zmm_t zmm_t8 = vtype::min(zmm[7], zmm8r);
    -    zmm_t zmm_t9 = vtype::permutexvar(rev_index, vtype::max(zmm[7], zmm8r));
    -    zmm_t zmm_t10 = vtype::permutexvar(rev_index, vtype::max(zmm[6], zmm9r));
    -    zmm_t zmm_t11 = vtype::permutexvar(rev_index, vtype::max(zmm[5], zmm10r));
    -    zmm_t zmm_t12 = vtype::permutexvar(rev_index, vtype::max(zmm[4], zmm11r));
    -    zmm_t zmm_t13 = vtype::permutexvar(rev_index, vtype::max(zmm[3], zmm12r));
    -    zmm_t zmm_t14 = vtype::permutexvar(rev_index, vtype::max(zmm[2], zmm13r));
    -    zmm_t zmm_t15 = vtype::permutexvar(rev_index, vtype::max(zmm[1], zmm14r));
    -    zmm_t zmm_t16 = vtype::permutexvar(rev_index, vtype::max(zmm[0], zmm15r));
    -    // Recusive half clear 16 zmm regs
    -    COEX(zmm_t1, zmm_t5);
    -    COEX(zmm_t2, zmm_t6);
    -    COEX(zmm_t3, zmm_t7);
    -    COEX(zmm_t4, zmm_t8);
    -    COEX(zmm_t9, zmm_t13);
    -    COEX(zmm_t10, zmm_t14);
    -    COEX(zmm_t11, zmm_t15);
    -    COEX(zmm_t12, zmm_t16);
    -    //
    -    COEX(zmm_t1, zmm_t3);
    -    COEX(zmm_t2, zmm_t4);
    -    COEX(zmm_t5, zmm_t7);
    -    COEX(zmm_t6, zmm_t8);
    -    COEX(zmm_t9, zmm_t11);
    -    COEX(zmm_t10, zmm_t12);
    -    COEX(zmm_t13, zmm_t15);
    -    COEX(zmm_t14, zmm_t16);
    -    //
    -    COEX(zmm_t1, zmm_t2);
    -    COEX(zmm_t3, zmm_t4);
    -    COEX(zmm_t5, zmm_t6);
    -    COEX(zmm_t7, zmm_t8);
    -    COEX(zmm_t9, zmm_t10);
    -    COEX(zmm_t11, zmm_t12);
    -    COEX(zmm_t13, zmm_t14);
    -    COEX(zmm_t15, zmm_t16);
    -    //
    -    zmm[0] = bitonic_merge_zmm_64bit(zmm_t1);
    -    zmm[1] = bitonic_merge_zmm_64bit(zmm_t2);
    -    zmm[2] = bitonic_merge_zmm_64bit(zmm_t3);
    -    zmm[3] = bitonic_merge_zmm_64bit(zmm_t4);
    -    zmm[4] = bitonic_merge_zmm_64bit(zmm_t5);
    -    zmm[5] = bitonic_merge_zmm_64bit(zmm_t6);
    -    zmm[6] = bitonic_merge_zmm_64bit(zmm_t7);
    -    zmm[7] = bitonic_merge_zmm_64bit(zmm_t8);
    -    zmm[8] = bitonic_merge_zmm_64bit(zmm_t9);
    -    zmm[9] = bitonic_merge_zmm_64bit(zmm_t10);
    -    zmm[10] = bitonic_merge_zmm_64bit(zmm_t11);
    -    zmm[11] = bitonic_merge_zmm_64bit(zmm_t12);
    -    zmm[12] = bitonic_merge_zmm_64bit(zmm_t13);
    -    zmm[13] = bitonic_merge_zmm_64bit(zmm_t14);
    -    zmm[14] = bitonic_merge_zmm_64bit(zmm_t15);
    -    zmm[15] = bitonic_merge_zmm_64bit(zmm_t16);
    -}
     
    -template 
    -X86_SIMD_SORT_INLINE void bitonic_merge_32_zmm_64bit(zmm_t *zmm) {
    -    const __m512i rev_index = _mm512_set_epi64(NETWORK_64BIT_2);
    -    zmm_t zmm16r = vtype::permutexvar(rev_index, zmm[16]);
    -    zmm_t zmm17r = vtype::permutexvar(rev_index, zmm[17]);
    -    zmm_t zmm18r = vtype::permutexvar(rev_index, zmm[18]);
    -    zmm_t zmm19r = vtype::permutexvar(rev_index, zmm[19]);
    -    zmm_t zmm20r = vtype::permutexvar(rev_index, zmm[20]);
    -    zmm_t zmm21r = vtype::permutexvar(rev_index, zmm[21]);
    -    zmm_t zmm22r = vtype::permutexvar(rev_index, zmm[22]);
    -    zmm_t zmm23r = vtype::permutexvar(rev_index, zmm[23]);
    -    zmm_t zmm24r = vtype::permutexvar(rev_index, zmm[24]);
    -    zmm_t zmm25r = vtype::permutexvar(rev_index, zmm[25]);
    -    zmm_t zmm26r = vtype::permutexvar(rev_index, zmm[26]);
    -    zmm_t zmm27r = vtype::permutexvar(rev_index, zmm[27]);
    -    zmm_t zmm28r = vtype::permutexvar(rev_index, zmm[28]);
    -    zmm_t zmm29r = vtype::permutexvar(rev_index, zmm[29]);
    -    zmm_t zmm30r = vtype::permutexvar(rev_index, zmm[30]);
    -    zmm_t zmm31r = vtype::permutexvar(rev_index, zmm[31]);
    -    zmm_t zmm_t1 = vtype::min(zmm[0], zmm31r);
    -    zmm_t zmm_t2 = vtype::min(zmm[1], zmm30r);
    -    zmm_t zmm_t3 = vtype::min(zmm[2], zmm29r);
    -    zmm_t zmm_t4 = vtype::min(zmm[3], zmm28r);
    -    zmm_t zmm_t5 = vtype::min(zmm[4], zmm27r);
    -    zmm_t zmm_t6 = vtype::min(zmm[5], zmm26r);
    -    zmm_t zmm_t7 = vtype::min(zmm[6], zmm25r);
    -    zmm_t zmm_t8 = vtype::min(zmm[7], zmm24r);
    -    zmm_t zmm_t9 = vtype::min(zmm[8], zmm23r);
    -    zmm_t zmm_t10 = vtype::min(zmm[9], zmm22r);
    -    zmm_t zmm_t11 = vtype::min(zmm[10], zmm21r);
    -    zmm_t zmm_t12 = vtype::min(zmm[11], zmm20r);
    -    zmm_t zmm_t13 = vtype::min(zmm[12], zmm19r);
    -    zmm_t zmm_t14 = vtype::min(zmm[13], zmm18r);
    -    zmm_t zmm_t15 = vtype::min(zmm[14], zmm17r);
    -    zmm_t zmm_t16 = vtype::min(zmm[15], zmm16r);
    -    zmm_t zmm_t17 = vtype::permutexvar(rev_index, vtype::max(zmm[15], zmm16r));
    -    zmm_t zmm_t18 = vtype::permutexvar(rev_index, vtype::max(zmm[14], zmm17r));
    -    zmm_t zmm_t19 = vtype::permutexvar(rev_index, vtype::max(zmm[13], zmm18r));
    -    zmm_t zmm_t20 = vtype::permutexvar(rev_index, vtype::max(zmm[12], zmm19r));
    -    zmm_t zmm_t21 = vtype::permutexvar(rev_index, vtype::max(zmm[11], zmm20r));
    -    zmm_t zmm_t22 = vtype::permutexvar(rev_index, vtype::max(zmm[10], zmm21r));
    -    zmm_t zmm_t23 = vtype::permutexvar(rev_index, vtype::max(zmm[9], zmm22r));
    -    zmm_t zmm_t24 = vtype::permutexvar(rev_index, vtype::max(zmm[8], zmm23r));
    -    zmm_t zmm_t25 = vtype::permutexvar(rev_index, vtype::max(zmm[7], zmm24r));
    -    zmm_t zmm_t26 = vtype::permutexvar(rev_index, vtype::max(zmm[6], zmm25r));
    -    zmm_t zmm_t27 = vtype::permutexvar(rev_index, vtype::max(zmm[5], zmm26r));
    -    zmm_t zmm_t28 = vtype::permutexvar(rev_index, vtype::max(zmm[4], zmm27r));
    -    zmm_t zmm_t29 = vtype::permutexvar(rev_index, vtype::max(zmm[3], zmm28r));
    -    zmm_t zmm_t30 = vtype::permutexvar(rev_index, vtype::max(zmm[2], zmm29r));
    -    zmm_t zmm_t31 = vtype::permutexvar(rev_index, vtype::max(zmm[1], zmm30r));
    -    zmm_t zmm_t32 = vtype::permutexvar(rev_index, vtype::max(zmm[0], zmm31r));
    -    // Recusive half clear 16 zmm regs
    -    COEX(zmm_t1, zmm_t9);
    -    COEX(zmm_t2, zmm_t10);
    -    COEX(zmm_t3, zmm_t11);
    -    COEX(zmm_t4, zmm_t12);
    -    COEX(zmm_t5, zmm_t13);
    -    COEX(zmm_t6, zmm_t14);
    -    COEX(zmm_t7, zmm_t15);
    -    COEX(zmm_t8, zmm_t16);
    -    COEX(zmm_t17, zmm_t25);
    -    COEX(zmm_t18, zmm_t26);
    -    COEX(zmm_t19, zmm_t27);
    -    COEX(zmm_t20, zmm_t28);
    -    COEX(zmm_t21, zmm_t29);
    -    COEX(zmm_t22, zmm_t30);
    -    COEX(zmm_t23, zmm_t31);
    -    COEX(zmm_t24, zmm_t32);
    -    //
    -    COEX(zmm_t1, zmm_t5);
    -    COEX(zmm_t2, zmm_t6);
    -    COEX(zmm_t3, zmm_t7);
    -    COEX(zmm_t4, zmm_t8);
    -    COEX(zmm_t9, zmm_t13);
    -    COEX(zmm_t10, zmm_t14);
    -    COEX(zmm_t11, zmm_t15);
    -    COEX(zmm_t12, zmm_t16);
    -    COEX(zmm_t17, zmm_t21);
    -    COEX(zmm_t18, zmm_t22);
    -    COEX(zmm_t19, zmm_t23);
    -    COEX(zmm_t20, zmm_t24);
    -    COEX(zmm_t25, zmm_t29);
    -    COEX(zmm_t26, zmm_t30);
    -    COEX(zmm_t27, zmm_t31);
    -    COEX(zmm_t28, zmm_t32);
    -    //
    -    COEX(zmm_t1, zmm_t3);
    -    COEX(zmm_t2, zmm_t4);
    -    COEX(zmm_t5, zmm_t7);
    -    COEX(zmm_t6, zmm_t8);
    -    COEX(zmm_t9, zmm_t11);
    -    COEX(zmm_t10, zmm_t12);
    -    COEX(zmm_t13, zmm_t15);
    -    COEX(zmm_t14, zmm_t16);
    -    COEX(zmm_t17, zmm_t19);
    -    COEX(zmm_t18, zmm_t20);
    -    COEX(zmm_t21, zmm_t23);
    -    COEX(zmm_t22, zmm_t24);
    -    COEX(zmm_t25, zmm_t27);
    -    COEX(zmm_t26, zmm_t28);
    -    COEX(zmm_t29, zmm_t31);
    -    COEX(zmm_t30, zmm_t32);
    -    //
    -    COEX(zmm_t1, zmm_t2);
    -    COEX(zmm_t3, zmm_t4);
    -    COEX(zmm_t5, zmm_t6);
    -    COEX(zmm_t7, zmm_t8);
    -    COEX(zmm_t9, zmm_t10);
    -    COEX(zmm_t11, zmm_t12);
    -    COEX(zmm_t13, zmm_t14);
    -    COEX(zmm_t15, zmm_t16);
    -    COEX(zmm_t17, zmm_t18);
    -    COEX(zmm_t19, zmm_t20);
    -    COEX(zmm_t21, zmm_t22);
    -    COEX(zmm_t23, zmm_t24);
    -    COEX(zmm_t25, zmm_t26);
    -    COEX(zmm_t27, zmm_t28);
    -    COEX(zmm_t29, zmm_t30);
    -    COEX(zmm_t31, zmm_t32);
    -    //
    -    zmm[0] = bitonic_merge_zmm_64bit(zmm_t1);
    -    zmm[1] = bitonic_merge_zmm_64bit(zmm_t2);
    -    zmm[2] = bitonic_merge_zmm_64bit(zmm_t3);
    -    zmm[3] = bitonic_merge_zmm_64bit(zmm_t4);
    -    zmm[4] = bitonic_merge_zmm_64bit(zmm_t5);
    -    zmm[5] = bitonic_merge_zmm_64bit(zmm_t6);
    -    zmm[6] = bitonic_merge_zmm_64bit(zmm_t7);
    -    zmm[7] = bitonic_merge_zmm_64bit(zmm_t8);
    -    zmm[8] = bitonic_merge_zmm_64bit(zmm_t9);
    -    zmm[9] = bitonic_merge_zmm_64bit(zmm_t10);
    -    zmm[10] = bitonic_merge_zmm_64bit(zmm_t11);
    -    zmm[11] = bitonic_merge_zmm_64bit(zmm_t12);
    -    zmm[12] = bitonic_merge_zmm_64bit(zmm_t13);
    -    zmm[13] = bitonic_merge_zmm_64bit(zmm_t14);
    -    zmm[14] = bitonic_merge_zmm_64bit(zmm_t15);
    -    zmm[15] = bitonic_merge_zmm_64bit(zmm_t16);
    -    zmm[16] = bitonic_merge_zmm_64bit(zmm_t17);
    -    zmm[17] = bitonic_merge_zmm_64bit(zmm_t18);
    -    zmm[18] = bitonic_merge_zmm_64bit(zmm_t19);
    -    zmm[19] = bitonic_merge_zmm_64bit(zmm_t20);
    -    zmm[20] = bitonic_merge_zmm_64bit(zmm_t21);
    -    zmm[21] = bitonic_merge_zmm_64bit(zmm_t22);
    -    zmm[22] = bitonic_merge_zmm_64bit(zmm_t23);
    -    zmm[23] = bitonic_merge_zmm_64bit(zmm_t24);
    -    zmm[24] = bitonic_merge_zmm_64bit(zmm_t25);
    -    zmm[25] = bitonic_merge_zmm_64bit(zmm_t26);
    -    zmm[26] = bitonic_merge_zmm_64bit(zmm_t27);
    -    zmm[27] = bitonic_merge_zmm_64bit(zmm_t28);
    -    zmm[28] = bitonic_merge_zmm_64bit(zmm_t29);
    -    zmm[29] = bitonic_merge_zmm_64bit(zmm_t30);
    -    zmm[30] = bitonic_merge_zmm_64bit(zmm_t31);
    -    zmm[31] = bitonic_merge_zmm_64bit(zmm_t32);
    -}
    +struct avx512_64bit_swizzle_ops {
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t swap_n(
    +        typename vtype::reg_t reg) {
    +        __m512i v = vtype::cast_to(reg);
     
    -template 
    -X86_SIMD_SORT_INLINE void sort_8_64bit(type_t *arr, int32_t N) {
    -    typename vtype::opmask_t load_mask = (0x01 << N) - 0x01;
    -    typename vtype::zmm_t zmm =
    -        vtype::mask_loadu(vtype::zmm_max(), load_mask, arr);
    -    vtype::mask_storeu(arr, load_mask, sort_zmm_64bit(zmm));
    -}
    -
    -template 
    -X86_SIMD_SORT_INLINE void sort_16_64bit(type_t *arr, int32_t N) {
    -    if (N <= 8) {
    -        sort_8_64bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    zmm_t zmm1 = vtype::loadu(arr);
    -    typename vtype::opmask_t load_mask = (0x01 << (N - 8)) - 0x01;
    -    zmm_t zmm2 = vtype::mask_loadu(vtype::zmm_max(), load_mask, arr + 8);
    -    zmm1 = sort_zmm_64bit(zmm1);
    -    zmm2 = sort_zmm_64bit(zmm2);
    -    bitonic_merge_two_zmm_64bit(zmm1, zmm2);
    -    vtype::storeu(arr, zmm1);
    -    vtype::mask_storeu(arr + 8, load_mask, zmm2);
    -}
    -
    -template 
    -X86_SIMD_SORT_INLINE void sort_32_64bit(type_t *arr, int32_t N) {
    -    if (N <= 16) {
    -        sort_16_64bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    using opmask_t = typename vtype::opmask_t;
    -    zmm_t zmm[4];
    -    zmm[0] = vtype::loadu(arr);
    -    zmm[1] = vtype::loadu(arr + 8);
    -    opmask_t load_mask1 = 0xFF, load_mask2 = 0xFF;
    -    uint64_t combined_mask = (0x1ull << (N - 16)) - 0x1ull;
    -    load_mask1 = (combined_mask)&0xFF;
    -    load_mask2 = (combined_mask >> 8) & 0xFF;
    -    zmm[2] = vtype::mask_loadu(vtype::zmm_max(), load_mask1, arr + 16);
    -    zmm[3] = vtype::mask_loadu(vtype::zmm_max(), load_mask2, arr + 24);
    -    zmm[0] = sort_zmm_64bit(zmm[0]);
    -    zmm[1] = sort_zmm_64bit(zmm[1]);
    -    zmm[2] = sort_zmm_64bit(zmm[2]);
    -    zmm[3] = sort_zmm_64bit(zmm[3]);
    -    bitonic_merge_two_zmm_64bit(zmm[0], zmm[1]);
    -    bitonic_merge_two_zmm_64bit(zmm[2], zmm[3]);
    -    bitonic_merge_four_zmm_64bit(zmm);
    -    vtype::storeu(arr, zmm[0]);
    -    vtype::storeu(arr + 8, zmm[1]);
    -    vtype::mask_storeu(arr + 16, load_mask1, zmm[2]);
    -    vtype::mask_storeu(arr + 24, load_mask2, zmm[3]);
    -}
    +        if constexpr (scale == 2) {
    +            v = _mm512_shuffle_epi32(v, (_MM_PERM_ENUM)0b01001110);
    +        } else if constexpr (scale == 4) {
    +            v = _mm512_shuffle_i64x2(v, v, 0b10110001);
    +        } else if constexpr (scale == 8) {
    +            v = _mm512_shuffle_i64x2(v, v, 0b01001110);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
     
    -template 
    -X86_SIMD_SORT_INLINE void sort_64_64bit(type_t *arr, int32_t N) {
    -    if (N <= 32) {
    -        sort_32_64bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    using opmask_t = typename vtype::opmask_t;
    -    zmm_t zmm[8];
    -    zmm[0] = vtype::loadu(arr);
    -    zmm[1] = vtype::loadu(arr + 8);
    -    zmm[2] = vtype::loadu(arr + 16);
    -    zmm[3] = vtype::loadu(arr + 24);
    -    zmm[0] = sort_zmm_64bit(zmm[0]);
    -    zmm[1] = sort_zmm_64bit(zmm[1]);
    -    zmm[2] = sort_zmm_64bit(zmm[2]);
    -    zmm[3] = sort_zmm_64bit(zmm[3]);
    -    opmask_t load_mask1 = 0xFF, load_mask2 = 0xFF;
    -    opmask_t load_mask3 = 0xFF, load_mask4 = 0xFF;
    -    // N-32 >= 1
    -    uint64_t combined_mask = (0x1ull << (N - 32)) - 0x1ull;
    -    load_mask1 = (combined_mask)&0xFF;
    -    load_mask2 = (combined_mask >> 8) & 0xFF;
    -    load_mask3 = (combined_mask >> 16) & 0xFF;
    -    load_mask4 = (combined_mask >> 24) & 0xFF;
    -    zmm[4] = vtype::mask_loadu(vtype::zmm_max(), load_mask1, arr + 32);
    -    zmm[5] = vtype::mask_loadu(vtype::zmm_max(), load_mask2, arr + 40);
    -    zmm[6] = vtype::mask_loadu(vtype::zmm_max(), load_mask3, arr + 48);
    -    zmm[7] = vtype::mask_loadu(vtype::zmm_max(), load_mask4, arr + 56);
    -    zmm[4] = sort_zmm_64bit(zmm[4]);
    -    zmm[5] = sort_zmm_64bit(zmm[5]);
    -    zmm[6] = sort_zmm_64bit(zmm[6]);
    -    zmm[7] = sort_zmm_64bit(zmm[7]);
    -    bitonic_merge_two_zmm_64bit(zmm[0], zmm[1]);
    -    bitonic_merge_two_zmm_64bit(zmm[2], zmm[3]);
    -    bitonic_merge_two_zmm_64bit(zmm[4], zmm[5]);
    -    bitonic_merge_two_zmm_64bit(zmm[6], zmm[7]);
    -    bitonic_merge_four_zmm_64bit(zmm);
    -    bitonic_merge_four_zmm_64bit(zmm + 4);
    -    bitonic_merge_eight_zmm_64bit(zmm);
    -    vtype::storeu(arr, zmm[0]);
    -    vtype::storeu(arr + 8, zmm[1]);
    -    vtype::storeu(arr + 16, zmm[2]);
    -    vtype::storeu(arr + 24, zmm[3]);
    -    vtype::mask_storeu(arr + 32, load_mask1, zmm[4]);
    -    vtype::mask_storeu(arr + 40, load_mask2, zmm[5]);
    -    vtype::mask_storeu(arr + 48, load_mask3, zmm[6]);
    -    vtype::mask_storeu(arr + 56, load_mask4, zmm[7]);
    -}
    +        return vtype::cast_from(v);
    +    }
     
    -template 
    -X86_SIMD_SORT_INLINE void sort_128_64bit(type_t *arr, int32_t N) {
    -    if (N <= 64) {
    -        sort_64_64bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    using opmask_t = typename vtype::opmask_t;
    -    zmm_t zmm[16];
    -    zmm[0] = vtype::loadu(arr);
    -    zmm[1] = vtype::loadu(arr + 8);
    -    zmm[2] = vtype::loadu(arr + 16);
    -    zmm[3] = vtype::loadu(arr + 24);
    -    zmm[4] = vtype::loadu(arr + 32);
    -    zmm[5] = vtype::loadu(arr + 40);
    -    zmm[6] = vtype::loadu(arr + 48);
    -    zmm[7] = vtype::loadu(arr + 56);
    -    zmm[0] = sort_zmm_64bit(zmm[0]);
    -    zmm[1] = sort_zmm_64bit(zmm[1]);
    -    zmm[2] = sort_zmm_64bit(zmm[2]);
    -    zmm[3] = sort_zmm_64bit(zmm[3]);
    -    zmm[4] = sort_zmm_64bit(zmm[4]);
    -    zmm[5] = sort_zmm_64bit(zmm[5]);
    -    zmm[6] = sort_zmm_64bit(zmm[6]);
    -    zmm[7] = sort_zmm_64bit(zmm[7]);
    -    opmask_t load_mask1 = 0xFF, load_mask2 = 0xFF;
    -    opmask_t load_mask3 = 0xFF, load_mask4 = 0xFF;
    -    opmask_t load_mask5 = 0xFF, load_mask6 = 0xFF;
    -    opmask_t load_mask7 = 0xFF, load_mask8 = 0xFF;
    -    if (N != 128) {
    -        uint64_t combined_mask = (0x1ull << (N - 64)) - 0x1ull;
    -        load_mask1 = (combined_mask)&0xFF;
    -        load_mask2 = (combined_mask >> 8) & 0xFF;
    -        load_mask3 = (combined_mask >> 16) & 0xFF;
    -        load_mask4 = (combined_mask >> 24) & 0xFF;
    -        load_mask5 = (combined_mask >> 32) & 0xFF;
    -        load_mask6 = (combined_mask >> 40) & 0xFF;
    -        load_mask7 = (combined_mask >> 48) & 0xFF;
    -        load_mask8 = (combined_mask >> 56) & 0xFF;
    -    }
    -    zmm[8] = vtype::mask_loadu(vtype::zmm_max(), load_mask1, arr + 64);
    -    zmm[9] = vtype::mask_loadu(vtype::zmm_max(), load_mask2, arr + 72);
    -    zmm[10] = vtype::mask_loadu(vtype::zmm_max(), load_mask3, arr + 80);
    -    zmm[11] = vtype::mask_loadu(vtype::zmm_max(), load_mask4, arr + 88);
    -    zmm[12] = vtype::mask_loadu(vtype::zmm_max(), load_mask5, arr + 96);
    -    zmm[13] = vtype::mask_loadu(vtype::zmm_max(), load_mask6, arr + 104);
    -    zmm[14] = vtype::mask_loadu(vtype::zmm_max(), load_mask7, arr + 112);
    -    zmm[15] = vtype::mask_loadu(vtype::zmm_max(), load_mask8, arr + 120);
    -    zmm[8] = sort_zmm_64bit(zmm[8]);
    -    zmm[9] = sort_zmm_64bit(zmm[9]);
    -    zmm[10] = sort_zmm_64bit(zmm[10]);
    -    zmm[11] = sort_zmm_64bit(zmm[11]);
    -    zmm[12] = sort_zmm_64bit(zmm[12]);
    -    zmm[13] = sort_zmm_64bit(zmm[13]);
    -    zmm[14] = sort_zmm_64bit(zmm[14]);
    -    zmm[15] = sort_zmm_64bit(zmm[15]);
    -    bitonic_merge_two_zmm_64bit(zmm[0], zmm[1]);
    -    bitonic_merge_two_zmm_64bit(zmm[2], zmm[3]);
    -    bitonic_merge_two_zmm_64bit(zmm[4], zmm[5]);
    -    bitonic_merge_two_zmm_64bit(zmm[6], zmm[7]);
    -    bitonic_merge_two_zmm_64bit(zmm[8], zmm[9]);
    -    bitonic_merge_two_zmm_64bit(zmm[10], zmm[11]);
    -    bitonic_merge_two_zmm_64bit(zmm[12], zmm[13]);
    -    bitonic_merge_two_zmm_64bit(zmm[14], zmm[15]);
    -    bitonic_merge_four_zmm_64bit(zmm);
    -    bitonic_merge_four_zmm_64bit(zmm + 4);
    -    bitonic_merge_four_zmm_64bit(zmm + 8);
    -    bitonic_merge_four_zmm_64bit(zmm + 12);
    -    bitonic_merge_eight_zmm_64bit(zmm);
    -    bitonic_merge_eight_zmm_64bit(zmm + 8);
    -    bitonic_merge_sixteen_zmm_64bit(zmm);
    -    vtype::storeu(arr, zmm[0]);
    -    vtype::storeu(arr + 8, zmm[1]);
    -    vtype::storeu(arr + 16, zmm[2]);
    -    vtype::storeu(arr + 24, zmm[3]);
    -    vtype::storeu(arr + 32, zmm[4]);
    -    vtype::storeu(arr + 40, zmm[5]);
    -    vtype::storeu(arr + 48, zmm[6]);
    -    vtype::storeu(arr + 56, zmm[7]);
    -    vtype::mask_storeu(arr + 64, load_mask1, zmm[8]);
    -    vtype::mask_storeu(arr + 72, load_mask2, zmm[9]);
    -    vtype::mask_storeu(arr + 80, load_mask3, zmm[10]);
    -    vtype::mask_storeu(arr + 88, load_mask4, zmm[11]);
    -    vtype::mask_storeu(arr + 96, load_mask5, zmm[12]);
    -    vtype::mask_storeu(arr + 104, load_mask6, zmm[13]);
    -    vtype::mask_storeu(arr + 112, load_mask7, zmm[14]);
    -    vtype::mask_storeu(arr + 120, load_mask8, zmm[15]);
    -}
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t reverse_n(
    +        typename vtype::reg_t reg) {
    +        __m512i v = vtype::cast_to(reg);
     
    -template 
    -X86_SIMD_SORT_INLINE void sort_256_64bit(type_t *arr, int32_t N) {
    -    if (N <= 128) {
    -        sort_128_64bit(arr, N);
    -        return;
    -    }
    -    using zmm_t = typename vtype::zmm_t;
    -    using opmask_t = typename vtype::opmask_t;
    -    zmm_t zmm[32];
    -    zmm[0] = vtype::loadu(arr);
    -    zmm[1] = vtype::loadu(arr + 8);
    -    zmm[2] = vtype::loadu(arr + 16);
    -    zmm[3] = vtype::loadu(arr + 24);
    -    zmm[4] = vtype::loadu(arr + 32);
    -    zmm[5] = vtype::loadu(arr + 40);
    -    zmm[6] = vtype::loadu(arr + 48);
    -    zmm[7] = vtype::loadu(arr + 56);
    -    zmm[8] = vtype::loadu(arr + 64);
    -    zmm[9] = vtype::loadu(arr + 72);
    -    zmm[10] = vtype::loadu(arr + 80);
    -    zmm[11] = vtype::loadu(arr + 88);
    -    zmm[12] = vtype::loadu(arr + 96);
    -    zmm[13] = vtype::loadu(arr + 104);
    -    zmm[14] = vtype::loadu(arr + 112);
    -    zmm[15] = vtype::loadu(arr + 120);
    -    zmm[0] = sort_zmm_64bit(zmm[0]);
    -    zmm[1] = sort_zmm_64bit(zmm[1]);
    -    zmm[2] = sort_zmm_64bit(zmm[2]);
    -    zmm[3] = sort_zmm_64bit(zmm[3]);
    -    zmm[4] = sort_zmm_64bit(zmm[4]);
    -    zmm[5] = sort_zmm_64bit(zmm[5]);
    -    zmm[6] = sort_zmm_64bit(zmm[6]);
    -    zmm[7] = sort_zmm_64bit(zmm[7]);
    -    zmm[8] = sort_zmm_64bit(zmm[8]);
    -    zmm[9] = sort_zmm_64bit(zmm[9]);
    -    zmm[10] = sort_zmm_64bit(zmm[10]);
    -    zmm[11] = sort_zmm_64bit(zmm[11]);
    -    zmm[12] = sort_zmm_64bit(zmm[12]);
    -    zmm[13] = sort_zmm_64bit(zmm[13]);
    -    zmm[14] = sort_zmm_64bit(zmm[14]);
    -    zmm[15] = sort_zmm_64bit(zmm[15]);
    -    opmask_t load_mask1 = 0xFF, load_mask2 = 0xFF;
    -    opmask_t load_mask3 = 0xFF, load_mask4 = 0xFF;
    -    opmask_t load_mask5 = 0xFF, load_mask6 = 0xFF;
    -    opmask_t load_mask7 = 0xFF, load_mask8 = 0xFF;
    -    opmask_t load_mask9 = 0xFF, load_mask10 = 0xFF;
    -    opmask_t load_mask11 = 0xFF, load_mask12 = 0xFF;
    -    opmask_t load_mask13 = 0xFF, load_mask14 = 0xFF;
    -    opmask_t load_mask15 = 0xFF, load_mask16 = 0xFF;
    -    if (N != 256) {
    -        uint64_t combined_mask;
    -        if (N < 192) {
    -            combined_mask = (0x1ull << (N - 128)) - 0x1ull;
    -            load_mask1 = (combined_mask)&0xFF;
    -            load_mask2 = (combined_mask >> 8) & 0xFF;
    -            load_mask3 = (combined_mask >> 16) & 0xFF;
    -            load_mask4 = (combined_mask >> 24) & 0xFF;
    -            load_mask5 = (combined_mask >> 32) & 0xFF;
    -            load_mask6 = (combined_mask >> 40) & 0xFF;
    -            load_mask7 = (combined_mask >> 48) & 0xFF;
    -            load_mask8 = (combined_mask >> 56) & 0xFF;
    -            load_mask9 = 0x00;
    -            load_mask10 = 0x0;
    -            load_mask11 = 0x00;
    -            load_mask12 = 0x00;
    -            load_mask13 = 0x00;
    -            load_mask14 = 0x00;
    -            load_mask15 = 0x00;
    -            load_mask16 = 0x00;
    +        if constexpr (scale == 2) {
    +            return swap_n(reg);
    +        } else if constexpr (scale == 4) {
    +            constexpr uint64_t mask = 0b00011011;
    +            v = _mm512_permutex_epi64(v, mask);
    +        } else if constexpr (scale == 8) {
    +            return vtype::reverse(reg);
             } else {
    -            combined_mask = (0x1ull << (N - 192)) - 0x1ull;
    -            load_mask9 = (combined_mask)&0xFF;
    -            load_mask10 = (combined_mask >> 8) & 0xFF;
    -            load_mask11 = (combined_mask >> 16) & 0xFF;
    -            load_mask12 = (combined_mask >> 24) & 0xFF;
    -            load_mask13 = (combined_mask >> 32) & 0xFF;
    -            load_mask14 = (combined_mask >> 40) & 0xFF;
    -            load_mask15 = (combined_mask >> 48) & 0xFF;
    -            load_mask16 = (combined_mask >> 56) & 0xFF;
    +            static_assert(scale == -1, "should not be reached");
             }
    -    }
    -    zmm[16] = vtype::mask_loadu(vtype::zmm_max(), load_mask1, arr + 128);
    -    zmm[17] = vtype::mask_loadu(vtype::zmm_max(), load_mask2, arr + 136);
    -    zmm[18] = vtype::mask_loadu(vtype::zmm_max(), load_mask3, arr + 144);
    -    zmm[19] = vtype::mask_loadu(vtype::zmm_max(), load_mask4, arr + 152);
    -    zmm[20] = vtype::mask_loadu(vtype::zmm_max(), load_mask5, arr + 160);
    -    zmm[21] = vtype::mask_loadu(vtype::zmm_max(), load_mask6, arr + 168);
    -    zmm[22] = vtype::mask_loadu(vtype::zmm_max(), load_mask7, arr + 176);
    -    zmm[23] = vtype::mask_loadu(vtype::zmm_max(), load_mask8, arr + 184);
    -    if (N < 192) {
    -        zmm[24] = vtype::zmm_max();
    -        zmm[25] = vtype::zmm_max();
    -        zmm[26] = vtype::zmm_max();
    -        zmm[27] = vtype::zmm_max();
    -        zmm[28] = vtype::zmm_max();
    -        zmm[29] = vtype::zmm_max();
    -        zmm[30] = vtype::zmm_max();
    -        zmm[31] = vtype::zmm_max();
    -    } else {
    -        zmm[24] = vtype::mask_loadu(vtype::zmm_max(), load_mask9, arr + 192);
    -        zmm[25] = vtype::mask_loadu(vtype::zmm_max(), load_mask10, arr + 200);
    -        zmm[26] = vtype::mask_loadu(vtype::zmm_max(), load_mask11, arr + 208);
    -        zmm[27] = vtype::mask_loadu(vtype::zmm_max(), load_mask12, arr + 216);
    -        zmm[28] = vtype::mask_loadu(vtype::zmm_max(), load_mask13, arr + 224);
    -        zmm[29] = vtype::mask_loadu(vtype::zmm_max(), load_mask14, arr + 232);
    -        zmm[30] = vtype::mask_loadu(vtype::zmm_max(), load_mask15, arr + 240);
    -        zmm[31] = vtype::mask_loadu(vtype::zmm_max(), load_mask16, arr + 248);
    -    }
    -    zmm[16] = sort_zmm_64bit(zmm[16]);
    -    zmm[17] = sort_zmm_64bit(zmm[17]);
    -    zmm[18] = sort_zmm_64bit(zmm[18]);
    -    zmm[19] = sort_zmm_64bit(zmm[19]);
    -    zmm[20] = sort_zmm_64bit(zmm[20]);
    -    zmm[21] = sort_zmm_64bit(zmm[21]);
    -    zmm[22] = sort_zmm_64bit(zmm[22]);
    -    zmm[23] = sort_zmm_64bit(zmm[23]);
    -    zmm[24] = sort_zmm_64bit(zmm[24]);
    -    zmm[25] = sort_zmm_64bit(zmm[25]);
    -    zmm[26] = sort_zmm_64bit(zmm[26]);
    -    zmm[27] = sort_zmm_64bit(zmm[27]);
    -    zmm[28] = sort_zmm_64bit(zmm[28]);
    -    zmm[29] = sort_zmm_64bit(zmm[29]);
    -    zmm[30] = sort_zmm_64bit(zmm[30]);
    -    zmm[31] = sort_zmm_64bit(zmm[31]);
    -    bitonic_merge_two_zmm_64bit(zmm[0], zmm[1]);
    -    bitonic_merge_two_zmm_64bit(zmm[2], zmm[3]);
    -    bitonic_merge_two_zmm_64bit(zmm[4], zmm[5]);
    -    bitonic_merge_two_zmm_64bit(zmm[6], zmm[7]);
    -    bitonic_merge_two_zmm_64bit(zmm[8], zmm[9]);
    -    bitonic_merge_two_zmm_64bit(zmm[10], zmm[11]);
    -    bitonic_merge_two_zmm_64bit(zmm[12], zmm[13]);
    -    bitonic_merge_two_zmm_64bit(zmm[14], zmm[15]);
    -    bitonic_merge_two_zmm_64bit(zmm[16], zmm[17]);
    -    bitonic_merge_two_zmm_64bit(zmm[18], zmm[19]);
    -    bitonic_merge_two_zmm_64bit(zmm[20], zmm[21]);
    -    bitonic_merge_two_zmm_64bit(zmm[22], zmm[23]);
    -    bitonic_merge_two_zmm_64bit(zmm[24], zmm[25]);
    -    bitonic_merge_two_zmm_64bit(zmm[26], zmm[27]);
    -    bitonic_merge_two_zmm_64bit(zmm[28], zmm[29]);
    -    bitonic_merge_two_zmm_64bit(zmm[30], zmm[31]);
    -    bitonic_merge_four_zmm_64bit(zmm);
    -    bitonic_merge_four_zmm_64bit(zmm + 4);
    -    bitonic_merge_four_zmm_64bit(zmm + 8);
    -    bitonic_merge_four_zmm_64bit(zmm + 12);
    -    bitonic_merge_four_zmm_64bit(zmm + 16);
    -    bitonic_merge_four_zmm_64bit(zmm + 20);
    -    bitonic_merge_four_zmm_64bit(zmm + 24);
    -    bitonic_merge_four_zmm_64bit(zmm + 28);
    -    bitonic_merge_eight_zmm_64bit(zmm);
    -    bitonic_merge_eight_zmm_64bit(zmm + 8);
    -    bitonic_merge_eight_zmm_64bit(zmm + 16);
    -    bitonic_merge_eight_zmm_64bit(zmm + 24);
    -    bitonic_merge_sixteen_zmm_64bit(zmm);
    -    bitonic_merge_sixteen_zmm_64bit(zmm + 16);
    -    bitonic_merge_32_zmm_64bit(zmm);
    -    vtype::storeu(arr, zmm[0]);
    -    vtype::storeu(arr + 8, zmm[1]);
    -    vtype::storeu(arr + 16, zmm[2]);
    -    vtype::storeu(arr + 24, zmm[3]);
    -    vtype::storeu(arr + 32, zmm[4]);
    -    vtype::storeu(arr + 40, zmm[5]);
    -    vtype::storeu(arr + 48, zmm[6]);
    -    vtype::storeu(arr + 56, zmm[7]);
    -    vtype::storeu(arr + 64, zmm[8]);
    -    vtype::storeu(arr + 72, zmm[9]);
    -    vtype::storeu(arr + 80, zmm[10]);
    -    vtype::storeu(arr + 88, zmm[11]);
    -    vtype::storeu(arr + 96, zmm[12]);
    -    vtype::storeu(arr + 104, zmm[13]);
    -    vtype::storeu(arr + 112, zmm[14]);
    -    vtype::storeu(arr + 120, zmm[15]);
    -    vtype::mask_storeu(arr + 128, load_mask1, zmm[16]);
    -    vtype::mask_storeu(arr + 136, load_mask2, zmm[17]);
    -    vtype::mask_storeu(arr + 144, load_mask3, zmm[18]);
    -    vtype::mask_storeu(arr + 152, load_mask4, zmm[19]);
    -    vtype::mask_storeu(arr + 160, load_mask5, zmm[20]);
    -    vtype::mask_storeu(arr + 168, load_mask6, zmm[21]);
    -    vtype::mask_storeu(arr + 176, load_mask7, zmm[22]);
    -    vtype::mask_storeu(arr + 184, load_mask8, zmm[23]);
    -    if (N > 192) {
    -        vtype::mask_storeu(arr + 192, load_mask9, zmm[24]);
    -        vtype::mask_storeu(arr + 200, load_mask10, zmm[25]);
    -        vtype::mask_storeu(arr + 208, load_mask11, zmm[26]);
    -        vtype::mask_storeu(arr + 216, load_mask12, zmm[27]);
    -        vtype::mask_storeu(arr + 224, load_mask13, zmm[28]);
    -        vtype::mask_storeu(arr + 232, load_mask14, zmm[29]);
    -        vtype::mask_storeu(arr + 240, load_mask15, zmm[30]);
    -        vtype::mask_storeu(arr + 248, load_mask16, zmm[31]);
    -    }
    -}
     
    -template 
    -static void qsort_64bit_(type_t *arr, int64_t left, int64_t right,
    -                         int64_t max_iters) {
    -    /*
    -     * Resort to std::sort if quicksort isnt making any progress
    -     */
    -    if (max_iters <= 0) {
    -        std::sort(arr + left, arr + right + 1);
    -        return;
    -    }
    -    /*
    -     * Base case: use bitonic networks to sort arrays <= 128
    -     */
    -    if (right + 1 - left <= 256) {
    -        sort_256_64bit(arr + left, (int32_t)(right + 1 - left));
    -        return;
    +        return vtype::cast_from(v);
         }
     
    -    type_t pivot = get_pivot_scalar(arr, left, right);
    -    type_t smallest = vtype::type_max();
    -    type_t biggest = vtype::type_min();
    -    int64_t pivot_index = partition_avx512_unrolled(
    -        arr, left, right + 1, pivot, &smallest, &biggest, false);
    -    if (pivot != smallest)
    -        qsort_64bit_(arr, left, pivot_index - 1, max_iters - 1);
    -    if (pivot != biggest)
    -        qsort_64bit_(arr, pivot_index, right, max_iters - 1);
    -}
    +    template 
    +    X86_SIMD_SORT_INLINE typename vtype::reg_t merge_n(
    +        typename vtype::reg_t reg, typename vtype::reg_t other) {
    +        __m512i v1 = vtype::cast_to(reg);
    +        __m512i v2 = vtype::cast_to(other);
     
    -template <>
    -void inline avx512_qsort(int64_t *arr, int64_t fromIndex, int64_t toIndex) {
    -    int64_t arrsize = toIndex - fromIndex;
    -    if (arrsize > 1) {
    -        qsort_64bit_, int64_t>(arr, fromIndex, toIndex - 1,
    -                                                   2 * (int64_t)log2(arrsize));
    -    }
    -}
    +        if constexpr (scale == 2) {
    +            v1 = _mm512_mask_blend_epi64(0b01010101, v1, v2);
    +        } else if constexpr (scale == 4) {
    +            v1 = _mm512_mask_blend_epi64(0b00110011, v1, v2);
    +        } else if constexpr (scale == 8) {
    +            v1 = _mm512_mask_blend_epi64(0b00001111, v1, v2);
    +        } else {
    +            static_assert(scale == -1, "should not be reached");
    +        }
     
    -template <>
    -void inline avx512_qsort(double *arr, int64_t fromIndex, int64_t toIndex) {
    -    int64_t arrsize = toIndex - fromIndex;
    -    if (arrsize > 1) {
    -        qsort_64bit_, double>(arr, fromIndex, toIndex - 1,
    -                                                 2 * (int64_t)log2(arrsize));
    +        return vtype::cast_from(v1);
         }
    -}
    +};
     
    -#endif  // AVX512_QSORT_64BIT
    +#endif
    diff --git a/src/java.base/linux/native/libsimdsort/avx512-common-qsort.h b/src/java.base/linux/native/libsimdsort/avx512-common-qsort.h
    deleted file mode 100644
    index 7e1c1e31a31..00000000000
    --- a/src/java.base/linux/native/libsimdsort/avx512-common-qsort.h
    +++ /dev/null
    @@ -1,483 +0,0 @@
    -/*
    - * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    - * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    - *
    - * This code is free software; you can redistribute it and/or modify it
    - * under the terms of the GNU General Public License version 2 only, as
    - * published by the Free Software Foundation.
    - *
    - * This code is distributed in the hope that it will be useful, but WITHOUT
    - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    - * version 2 for more details (a copy is included in the LICENSE file that
    - * accompanied this code).
    - *
    - * You should have received a copy of the GNU General Public License version
    - * 2 along with this work; if not, write to the Free Software Foundation,
    - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    - *
    - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    - * or visit www.oracle.com if you need additional information or have any
    - * questions.
    - *
    - */
    -
    -// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    -#ifndef AVX512_QSORT_COMMON
    -#define AVX512_QSORT_COMMON
    -
    -/*
    - * Quicksort using AVX-512. The ideas and code are based on these two research
    - * papers [1] and [2]. On a high level, the idea is to vectorize quicksort
    - * partitioning using AVX-512 compressstore instructions. If the array size is
    - * < 128, then use Bitonic sorting network implemented on 512-bit registers.
    - * The precise network definitions depend on the dtype and are defined in
    - * separate files: avx512-16bit-qsort.hpp, avx512-32bit-qsort.hpp and
    - * avx512-64bit-qsort.hpp. Article [4] is a good resource for bitonic sorting
    - * network. The core implementations of the vectorized qsort functions
    - * avx512_qsort(T*, int64_t) are modified versions of avx2 quicksort
    - * presented in the paper [2] and source code associated with that paper [3].
    - *
    - * [1] Fast and Robust Vectorized In-Place Sorting of Primitive Types
    - *     https://drops.dagstuhl.de/opus/volltexte/2021/13775/
    - *
    - * [2] A Novel Hybrid Quicksort Algorithm Vectorized using AVX-512 on Intel
    - * Skylake https://arxiv.org/pdf/1704.08579.pdf
    - *
    - * [3] https://github.com/simd-sorting/fast-and-robust: SPDX-License-Identifier:
    - * MIT
    - *
    - * [4]
    - * http://mitp-content-server.mit.edu:18180/books/content/sectbyfn?collid=books_pres_0&fn=Chapter%2027.pdf&id=8030
    - *
    - */
    -
    -#include 
    -#include 
    -#include 
    -#include 
    -#include 
    -
    -/*
    -Workaround for the bug in GCC12 (that was fixed in GCC 12.3.1).
    -More details are available at: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105593
    -*/
    -#pragma GCC diagnostic push
    -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
    -#pragma GCC diagnostic ignored "-Wuninitialized"
    -#include 
    -#pragma GCC diagnostic pop
    -
    -#define X86_SIMD_SORT_INFINITY std::numeric_limits::infinity()
    -#define X86_SIMD_SORT_INFINITYF std::numeric_limits::infinity()
    -#define X86_SIMD_SORT_INFINITYH 0x7c00
    -#define X86_SIMD_SORT_NEGINFINITYH 0xfc00
    -#define X86_SIMD_SORT_MAX_UINT16 std::numeric_limits::max()
    -#define X86_SIMD_SORT_MAX_INT16 std::numeric_limits::max()
    -#define X86_SIMD_SORT_MIN_INT16 std::numeric_limits::min()
    -#define X86_SIMD_SORT_MAX_UINT32 std::numeric_limits::max()
    -#define X86_SIMD_SORT_MAX_INT32 std::numeric_limits::max()
    -#define X86_SIMD_SORT_MIN_INT32 std::numeric_limits::min()
    -#define X86_SIMD_SORT_MAX_UINT64 std::numeric_limits::max()
    -#define X86_SIMD_SORT_MAX_INT64 std::numeric_limits::max()
    -#define X86_SIMD_SORT_MIN_INT64 std::numeric_limits::min()
    -#define ZMM_MAX_DOUBLE _mm512_set1_pd(X86_SIMD_SORT_INFINITY)
    -#define ZMM_MAX_UINT64 _mm512_set1_epi64(X86_SIMD_SORT_MAX_UINT64)
    -#define ZMM_MAX_INT64 _mm512_set1_epi64(X86_SIMD_SORT_MAX_INT64)
    -#define ZMM_MAX_FLOAT _mm512_set1_ps(X86_SIMD_SORT_INFINITYF)
    -#define ZMM_MAX_UINT _mm512_set1_epi32(X86_SIMD_SORT_MAX_UINT32)
    -#define ZMM_MAX_INT _mm512_set1_epi32(X86_SIMD_SORT_MAX_INT32)
    -#define ZMM_MAX_HALF _mm512_set1_epi16(X86_SIMD_SORT_INFINITYH)
    -#define YMM_MAX_HALF _mm256_set1_epi16(X86_SIMD_SORT_INFINITYH)
    -#define ZMM_MAX_UINT16 _mm512_set1_epi16(X86_SIMD_SORT_MAX_UINT16)
    -#define ZMM_MAX_INT16 _mm512_set1_epi16(X86_SIMD_SORT_MAX_INT16)
    -#define SHUFFLE_MASK(a, b, c, d) (a << 6) | (b << 4) | (c << 2) | d
    -
    -#ifdef _MSC_VER
    -#define X86_SIMD_SORT_INLINE static inline
    -#define X86_SIMD_SORT_FINLINE static __forceinline
    -#elif defined(__CYGWIN__)
    -/*
    - * Force inline in cygwin to work around a compiler bug. See
    - * https://github.com/numpy/numpy/pull/22315#issuecomment-1267757584
    - */
    -#define X86_SIMD_SORT_INLINE static __attribute__((always_inline))
    -#define X86_SIMD_SORT_FINLINE static __attribute__((always_inline))
    -#elif defined(__GNUC__)
    -#define X86_SIMD_SORT_INLINE static inline
    -#define X86_SIMD_SORT_FINLINE static __attribute__((always_inline))
    -#else
    -#define X86_SIMD_SORT_INLINE static
    -#define X86_SIMD_SORT_FINLINE static
    -#endif
    -
    -#define LIKELY(x) __builtin_expect((x), 1)
    -#define UNLIKELY(x) __builtin_expect((x), 0)
    -
    -template 
    -struct zmm_vector;
    -
    -template 
    -struct ymm_vector;
    -
    -// Regular quicksort routines:
    -template 
    -void avx512_qsort(T *arr, int64_t arrsize);
    -
    -template 
    -void inline avx512_qsort(T *arr, int64_t from_index, int64_t to_index);
    -
    -template 
    -bool is_a_nan(T elem) {
    -    return std::isnan(elem);
    -}
    -
    -template 
    -X86_SIMD_SORT_INLINE T get_pivot_scalar(T *arr, const int64_t left, const int64_t right) {
    -    // median of 8 equally spaced elements
    -    int64_t NUM_ELEMENTS = 8;
    -    int64_t MID = NUM_ELEMENTS / 2;
    -    int64_t size = (right - left) / NUM_ELEMENTS;
    -    T temp[NUM_ELEMENTS];
    -    for (int64_t i = 0; i < NUM_ELEMENTS; i++) temp[i] = arr[left + (i * size)];
    -    std::sort(temp, temp + NUM_ELEMENTS);
    -    return temp[MID];
    -}
    -
    -template 
    -bool comparison_func_ge(const T &a, const T &b) {
    -    return a < b;
    -}
    -
    -template 
    -bool comparison_func_gt(const T &a, const T &b) {
    -    return a <= b;
    -}
    -
    -/*
    - * COEX == Compare and Exchange two registers by swapping min and max values
    - */
    -template 
    -static void COEX(mm_t &a, mm_t &b) {
    -    mm_t temp = a;
    -    a = vtype::min(a, b);
    -    b = vtype::max(temp, b);
    -}
    -template 
    -static inline zmm_t cmp_merge(zmm_t in1, zmm_t in2, opmask_t mask) {
    -    zmm_t min = vtype::min(in2, in1);
    -    zmm_t max = vtype::max(in2, in1);
    -    return vtype::mask_mov(min, mask, max);  // 0 -> min, 1 -> max
    -}
    -/*
    - * Parition one ZMM register based on the pivot and returns the
    - * number of elements that are greater than or equal to the pivot.
    - */
    -template 
    -static inline int32_t partition_vec(type_t *arr, int64_t left, int64_t right,
    -                                    const zmm_t curr_vec, const zmm_t pivot_vec,
    -                                    zmm_t *smallest_vec, zmm_t *biggest_vec, bool use_gt) {
    -    /* which elements are larger than or equal to the pivot */
    -    typename vtype::opmask_t mask;
    -    if (use_gt) mask = vtype::gt(curr_vec, pivot_vec);
    -    else mask = vtype::ge(curr_vec, pivot_vec);
    -    //mask = vtype::ge(curr_vec, pivot_vec);
    -    int32_t amount_ge_pivot = _mm_popcnt_u32((int32_t)mask);
    -    vtype::mask_compressstoreu(arr + left, vtype::knot_opmask(mask),
    -                               curr_vec);
    -    vtype::mask_compressstoreu(arr + right - amount_ge_pivot, mask,
    -                               curr_vec);
    -    *smallest_vec = vtype::min(curr_vec, *smallest_vec);
    -    *biggest_vec = vtype::max(curr_vec, *biggest_vec);
    -    return amount_ge_pivot;
    -}
    -/*
    - * Parition an array based on the pivot and returns the index of the
    - * first element that is greater than or equal to the pivot.
    - */
    -template 
    -static inline int64_t partition_avx512(type_t *arr, int64_t left, int64_t right,
    -                                       type_t pivot, type_t *smallest,
    -                                       type_t *biggest, bool use_gt) {
    -    auto comparison_func = use_gt ? comparison_func_gt : comparison_func_ge;
    -    /* make array length divisible by vtype::numlanes , shortening the array */
    -    for (int32_t i = (right - left) % vtype::numlanes; i > 0; --i) {
    -        *smallest = std::min(*smallest, arr[left], comparison_func);
    -        *biggest = std::max(*biggest, arr[left], comparison_func);
    -        if (!comparison_func(arr[left], pivot)) {
    -            std::swap(arr[left], arr[--right]);
    -        } else {
    -            ++left;
    -        }
    -    }
    -
    -    if (left == right)
    -        return left; /* less than vtype::numlanes elements in the array */
    -
    -    using zmm_t = typename vtype::zmm_t;
    -    zmm_t pivot_vec = vtype::set1(pivot);
    -    zmm_t min_vec = vtype::set1(*smallest);
    -    zmm_t max_vec = vtype::set1(*biggest);
    -
    -    if (right - left == vtype::numlanes) {
    -        zmm_t vec = vtype::loadu(arr + left);
    -        int32_t amount_ge_pivot =
    -            partition_vec(arr, left, left + vtype::numlanes, vec,
    -                                 pivot_vec, &min_vec, &max_vec, use_gt);
    -        *smallest = vtype::reducemin(min_vec);
    -        *biggest = vtype::reducemax(max_vec);
    -        return left + (vtype::numlanes - amount_ge_pivot);
    -    }
    -
    -    // first and last vtype::numlanes values are partitioned at the end
    -    zmm_t vec_left = vtype::loadu(arr + left);
    -    zmm_t vec_right = vtype::loadu(arr + (right - vtype::numlanes));
    -    // store points of the vectors
    -    int64_t r_store = right - vtype::numlanes;
    -    int64_t l_store = left;
    -    // indices for loading the elements
    -    left += vtype::numlanes;
    -    right -= vtype::numlanes;
    -    while (right - left != 0) {
    -        zmm_t curr_vec;
    -        /*
    -         * if fewer elements are stored on the right side of the array,
    -         * then next elements are loaded from the right side,
    -         * otherwise from the left side
    -         */
    -        if ((r_store + vtype::numlanes) - right < left - l_store) {
    -            right -= vtype::numlanes;
    -            curr_vec = vtype::loadu(arr + right);
    -        } else {
    -            curr_vec = vtype::loadu(arr + left);
    -            left += vtype::numlanes;
    -        }
    -        // partition the current vector and save it on both sides of the array
    -        int32_t amount_ge_pivot =
    -            partition_vec(arr, l_store, r_store + vtype::numlanes,
    -                                 curr_vec, pivot_vec, &min_vec, &max_vec, use_gt);
    -        ;
    -        r_store -= amount_ge_pivot;
    -        l_store += (vtype::numlanes - amount_ge_pivot);
    -    }
    -
    -    /* partition and save vec_left and vec_right */
    -    int32_t amount_ge_pivot =
    -        partition_vec(arr, l_store, r_store + vtype::numlanes, vec_left,
    -                             pivot_vec, &min_vec, &max_vec, use_gt);
    -    l_store += (vtype::numlanes - amount_ge_pivot);
    -    amount_ge_pivot =
    -        partition_vec(arr, l_store, l_store + vtype::numlanes, vec_right,
    -                             pivot_vec, &min_vec, &max_vec, use_gt);
    -    l_store += (vtype::numlanes - amount_ge_pivot);
    -    *smallest = vtype::reducemin(min_vec);
    -    *biggest = vtype::reducemax(max_vec);
    -    return l_store;
    -}
    -
    -template 
    -static inline int64_t partition_avx512_unrolled(type_t *arr, int64_t left,
    -                                                int64_t right, type_t pivot,
    -                                                type_t *smallest,
    -                                                type_t *biggest, bool use_gt) {
    -    if (right - left <= 2 * num_unroll * vtype::numlanes) {
    -        return partition_avx512(arr, left, right, pivot, smallest,
    -                                       biggest, use_gt);
    -    }
    -
    -    auto comparison_func = use_gt ? comparison_func_gt : comparison_func_ge;
    -    /* make array length divisible by 8*vtype::numlanes , shortening the array
    -     */
    -    for (int32_t i = ((right - left) % (num_unroll * vtype::numlanes)); i > 0;
    -         --i) {
    -        *smallest = std::min(*smallest, arr[left], comparison_func);
    -        *biggest = std::max(*biggest, arr[left], comparison_func);
    -        if (!comparison_func(arr[left], pivot)) {
    -            std::swap(arr[left], arr[--right]);
    -        } else {
    -            ++left;
    -        }
    -    }
    -
    -    if (left == right)
    -        return left; /* less than vtype::numlanes elements in the array */
    -
    -    using zmm_t = typename vtype::zmm_t;
    -    zmm_t pivot_vec = vtype::set1(pivot);
    -    zmm_t min_vec = vtype::set1(*smallest);
    -    zmm_t max_vec = vtype::set1(*biggest);
    -
    -    // We will now have atleast 16 registers worth of data to process:
    -    // left and right vtype::numlanes values are partitioned at the end
    -    zmm_t vec_left[num_unroll], vec_right[num_unroll];
    -#pragma GCC unroll 8
    -    for (int ii = 0; ii < num_unroll; ++ii) {
    -        vec_left[ii] = vtype::loadu(arr + left + vtype::numlanes * ii);
    -        vec_right[ii] =
    -            vtype::loadu(arr + (right - vtype::numlanes * (num_unroll - ii)));
    -    }
    -    // store points of the vectors
    -    int64_t r_store = right - vtype::numlanes;
    -    int64_t l_store = left;
    -    // indices for loading the elements
    -    left += num_unroll * vtype::numlanes;
    -    right -= num_unroll * vtype::numlanes;
    -    while (right - left != 0) {
    -        zmm_t curr_vec[num_unroll];
    -        /*
    -         * if fewer elements are stored on the right side of the array,
    -         * then next elements are loaded from the right side,
    -         * otherwise from the left side
    -         */
    -        if ((r_store + vtype::numlanes) - right < left - l_store) {
    -            right -= num_unroll * vtype::numlanes;
    -#pragma GCC unroll 8
    -            for (int ii = 0; ii < num_unroll; ++ii) {
    -                curr_vec[ii] = vtype::loadu(arr + right + ii * vtype::numlanes);
    -            }
    -        } else {
    -#pragma GCC unroll 8
    -            for (int ii = 0; ii < num_unroll; ++ii) {
    -                curr_vec[ii] = vtype::loadu(arr + left + ii * vtype::numlanes);
    -            }
    -            left += num_unroll * vtype::numlanes;
    -        }
    -// partition the current vector and save it on both sides of the array
    -#pragma GCC unroll 8
    -        for (int ii = 0; ii < num_unroll; ++ii) {
    -            int32_t amount_ge_pivot = partition_vec(
    -                arr, l_store, r_store + vtype::numlanes, curr_vec[ii],
    -                pivot_vec, &min_vec, &max_vec, use_gt);
    -            l_store += (vtype::numlanes - amount_ge_pivot);
    -            r_store -= amount_ge_pivot;
    -        }
    -    }
    -
    -/* partition and save vec_left[8] and vec_right[8] */
    -#pragma GCC unroll 8
    -    for (int ii = 0; ii < num_unroll; ++ii) {
    -        int32_t amount_ge_pivot =
    -            partition_vec(arr, l_store, r_store + vtype::numlanes,
    -                                 vec_left[ii], pivot_vec, &min_vec, &max_vec, use_gt);
    -        l_store += (vtype::numlanes - amount_ge_pivot);
    -        r_store -= amount_ge_pivot;
    -    }
    -#pragma GCC unroll 8
    -    for (int ii = 0; ii < num_unroll; ++ii) {
    -        int32_t amount_ge_pivot =
    -            partition_vec(arr, l_store, r_store + vtype::numlanes,
    -                                 vec_right[ii], pivot_vec, &min_vec, &max_vec, use_gt);
    -        l_store += (vtype::numlanes - amount_ge_pivot);
    -        r_store -= amount_ge_pivot;
    -    }
    -    *smallest = vtype::reducemin(min_vec);
    -    *biggest = vtype::reducemax(max_vec);
    -    return l_store;
    -}
    -
    -// to_index (exclusive)
    -template 
    -static int64_t vectorized_partition(type_t *arr, int64_t from_index, int64_t to_index, type_t pivot, bool use_gt) {
    -    type_t smallest = vtype::type_max();
    -    type_t biggest = vtype::type_min();
    -    int64_t pivot_index = partition_avx512_unrolled(
    -            arr, from_index, to_index, pivot, &smallest, &biggest, use_gt);
    -    return pivot_index;
    -}
    -
    -// partitioning functions
    -template 
    -void avx512_dual_pivot_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2){
    -    const T pivot1 = arr[index_pivot1];
    -    const T pivot2 = arr[index_pivot2];
    -
    -    const int64_t low = from_index;
    -    const int64_t high = to_index;
    -    const int64_t start = low + 1;
    -    const int64_t end = high - 1;
    -
    -
    -    std::swap(arr[index_pivot1], arr[low]);
    -    std::swap(arr[index_pivot2], arr[end]);
    -
    -
    -    const int64_t pivot_index2 = vectorized_partition, T>(arr, start, end, pivot2, true); // use_gt = true
    -    std::swap(arr[end], arr[pivot_index2]);
    -    int64_t upper = pivot_index2;
    -
    -    // if all other elements are greater than pivot2 (and pivot1), no need to do further partitioning
    -    if (upper == start) {
    -        pivot_indices[0] = low;
    -        pivot_indices[1] = upper;
    -        return;
    -    }
    -
    -    const int64_t pivot_index1 = vectorized_partition, T>(arr, start, upper, pivot1, false); // use_ge (use_gt = false)
    -    int64_t lower = pivot_index1 - 1;
    -    std::swap(arr[low], arr[lower]);
    -
    -    pivot_indices[0] = lower;
    -    pivot_indices[1] = upper;
    -}
    -
    -template 
    -void avx512_single_pivot_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot){
    -    const T pivot = arr[index_pivot];
    -
    -    const int64_t low = from_index;
    -    const int64_t high = to_index;
    -    const int64_t end = high - 1;
    -
    -
    -    const int64_t pivot_index1 = vectorized_partition, T>(arr, low, high, pivot, false); // use_gt = false (use_ge)
    -    int64_t lower = pivot_index1;
    -
    -    const int64_t pivot_index2 = vectorized_partition, T>(arr, pivot_index1, high, pivot, true); // use_gt = true
    -    int64_t upper = pivot_index2;
    -
    -    pivot_indices[0] = lower;
    -    pivot_indices[1] = upper;
    -}
    -
    -template 
    -void inline avx512_fast_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2) {
    -    if (index_pivot1 != index_pivot2) {
    -        avx512_dual_pivot_partition(arr, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    -    }
    -    else {
    -        avx512_single_pivot_partition(arr, from_index, to_index, pivot_indices, index_pivot1);
    -    }
    -}
    -
    -template 
    -void inline insertion_sort(T *arr, int32_t from_index, int32_t to_index) {
    -    for (int i, k = from_index; ++k < to_index; ) {
    -        T ai = arr[i = k];
    -
    -        if (ai < arr[i - 1]) {
    -            while (--i >= from_index && ai < arr[i]) {
    -                arr[i + 1] = arr[i];
    -            }
    -            arr[i + 1] = ai;
    -        }
    -    }
    -}
    -
    -template 
    -void inline avx512_fast_sort(T *arr, int64_t from_index, int64_t to_index, const int32_t INS_SORT_THRESHOLD) {
    -    int32_t size = to_index - from_index;
    -
    -    if (size <= INS_SORT_THRESHOLD) {
    -        insertion_sort(arr, from_index, to_index);
    -    }
    -    else {
    -        avx512_qsort(arr, from_index, to_index);
    -    }
    -}
    -
    -
    -
    -#endif  // AVX512_QSORT_COMMON
    diff --git a/src/java.base/linux/native/libsimdsort/avx512-linux-qsort.cpp b/src/java.base/linux/native/libsimdsort/avx512-linux-qsort.cpp
    index 6bd0c5871d6..35b71c421a5 100644
    --- a/src/java.base/linux/native/libsimdsort/avx512-linux-qsort.cpp
    +++ b/src/java.base/linux/native/libsimdsort/avx512-linux-qsort.cpp
    @@ -21,12 +21,15 @@
      * questions.
      *
      */
    +#include "simdsort-support.hpp"
    +#ifdef __SIMDSORT_SUPPORTED_LINUX
     
     #pragma GCC target("avx512dq", "avx512f")
     #include "avx512-32bit-qsort.hpp"
     #include "avx512-64bit-qsort.hpp"
     #include "classfile_constants.h"
     
    +
     #define DLL_PUBLIC __attribute__((visibility("default")))
     #define INSERTION_SORT_THRESHOLD_32BIT 16
     #define INSERTION_SORT_THRESHOLD_64BIT 20
    @@ -36,35 +39,41 @@ extern "C" {
         DLL_PUBLIC void avx512_sort(void *array, int elem_type, int32_t from_index, int32_t to_index) {
             switch(elem_type) {
                 case JVM_T_INT:
    -                avx512_fast_sort((int32_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
    +                avx512_fast_sort((int32_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
                     break;
                 case JVM_T_LONG:
    -                avx512_fast_sort((int64_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_64BIT);
    +                avx512_fast_sort((int64_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_64BIT);
                     break;
                 case JVM_T_FLOAT:
    -                avx512_fast_sort((float*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
    +                avx512_fast_sort((float*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
                     break;
                 case JVM_T_DOUBLE:
    -                avx512_fast_sort((double*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_64BIT);
    +                avx512_fast_sort((double*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_64BIT);
                     break;
    +            default:
    +                assert(false, "Unexpected type");
             }
         }
     
         DLL_PUBLIC void avx512_partition(void *array, int elem_type, int32_t from_index, int32_t to_index, int32_t *pivot_indices, int32_t index_pivot1, int32_t index_pivot2) {
             switch(elem_type) {
                 case JVM_T_INT:
    -                avx512_fast_partition((int32_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +                avx512_fast_partition((int32_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
                     break;
                 case JVM_T_LONG:
    -                avx512_fast_partition((int64_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +                avx512_fast_partition((int64_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
                     break;
                 case JVM_T_FLOAT:
    -                avx512_fast_partition((float*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +                avx512_fast_partition((float*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
                     break;
                 case JVM_T_DOUBLE:
    -                avx512_fast_partition((double*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +                avx512_fast_partition((double*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
                     break;
    +            default:
    +                assert(false, "Unexpected type");
             }
         }
     
     }
    +
    +#endif
    diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java b/src/java.base/linux/native/libsimdsort/simdsort-support.hpp
    similarity index 62%
    rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java
    rename to src/java.base/linux/native/libsimdsort/simdsort-support.hpp
    index a70a35daa63..f6946fdccec 100644
    --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java
    +++ b/src/java.base/linux/native/libsimdsort/simdsort-support.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023 Intel Corporation. All rights reserved.
      * 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,18 +22,18 @@
      *
      */
     
    -package gc.stress.gclocker;
    +#ifndef SIMDSORT_SUPPORT_HPP
    +#define SIMDSORT_SUPPORT_HPP
    +#include 
    +#include 
     
    -/*
    - * @test TestGCLockerWithG1
    - * @library /
    - * @requires vm.gc.G1
    - * @summary Stress G1's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen.
    - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseG1GC gc.stress.gclocker.TestGCLockerWithG1
    - */
    -public class TestGCLockerWithG1 {
    -    public static void main(String[] args) {
    -        String[] testArgs = {"2", "G1 Old Gen"};
    -        TestGCLocker.main(testArgs);
    -    }
    -}
    +#undef assert
    +#define assert(cond, msg) { if (!(cond)) { fprintf(stderr, "assert fails %s %d: %s\n", __FILE__, __LINE__, msg); abort(); }}
    +
    +
    +// GCC >= 9.1 is needed to build AVX2 portions of libsimdsort using C++17 features
    +#if defined(_LP64) && (defined(__GNUC__) && ((__GNUC__ > 9) || ((__GNUC__ == 9) && (__GNUC_MINOR__ >= 1))))
    +#define __SIMDSORT_SUPPORTED_LINUX
    +#endif
    +
    +#endif //SIMDSORT_SUPPORT_HPP
    \ No newline at end of file
    diff --git a/src/java.base/linux/native/libsimdsort/xss-common-includes.h b/src/java.base/linux/native/libsimdsort/xss-common-includes.h
    new file mode 100644
    index 00000000000..68121cf1b7d
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/xss-common-includes.h
    @@ -0,0 +1,101 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    +
    +#ifndef XSS_COMMON_INCLUDES
    +#define XSS_COMMON_INCLUDES
    +#include 
    +#include 
    +#include 
    +#include 
    +/*
    +Workaround for the bug in GCC12 (that was fixed in GCC 12.3.1).
    +More details are available at:
    +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105593
    +*/
    +#pragma GCC diagnostic push
    +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
    +#pragma GCC diagnostic ignored "-Wuninitialized"
    +#include 
    +#pragma GCC diagnostic pop
    +#include 
    +#include 
    +
    +#define X86_SIMD_SORT_INFINITY std::numeric_limits::infinity()
    +#define X86_SIMD_SORT_INFINITYF std::numeric_limits::infinity()
    +#define X86_SIMD_SORT_INFINITYH 0x7c00
    +#define X86_SIMD_SORT_NEGINFINITYH 0xfc00
    +#define X86_SIMD_SORT_MAX_UINT16 std::numeric_limits::max()
    +#define X86_SIMD_SORT_MAX_INT16 std::numeric_limits::max()
    +#define X86_SIMD_SORT_MIN_INT16 std::numeric_limits::min()
    +#define X86_SIMD_SORT_MAX_UINT32 std::numeric_limits::max()
    +#define X86_SIMD_SORT_MAX_INT32 std::numeric_limits::max()
    +#define X86_SIMD_SORT_MIN_INT32 std::numeric_limits::min()
    +#define X86_SIMD_SORT_MAX_UINT64 std::numeric_limits::max()
    +#define X86_SIMD_SORT_MAX_INT64 std::numeric_limits::max()
    +#define X86_SIMD_SORT_MIN_INT64 std::numeric_limits::min()
    +#define ZMM_MAX_DOUBLE _mm512_set1_pd(X86_SIMD_SORT_INFINITY)
    +#define ZMM_MAX_UINT64 _mm512_set1_epi64(X86_SIMD_SORT_MAX_UINT64)
    +#define ZMM_MAX_INT64 _mm512_set1_epi64(X86_SIMD_SORT_MAX_INT64)
    +#define ZMM_MAX_FLOAT _mm512_set1_ps(X86_SIMD_SORT_INFINITYF)
    +#define ZMM_MAX_UINT _mm512_set1_epi32(X86_SIMD_SORT_MAX_UINT32)
    +#define ZMM_MAX_INT _mm512_set1_epi32(X86_SIMD_SORT_MAX_INT32)
    +#define ZMM_MAX_HALF _mm512_set1_epi16(X86_SIMD_SORT_INFINITYH)
    +#define YMM_MAX_HALF _mm256_set1_epi16(X86_SIMD_SORT_INFINITYH)
    +#define ZMM_MAX_UINT16 _mm512_set1_epi16(X86_SIMD_SORT_MAX_UINT16)
    +#define ZMM_MAX_INT16 _mm512_set1_epi16(X86_SIMD_SORT_MAX_INT16)
    +#define SHUFFLE_MASK(a, b, c, d) (a << 6) | (b << 4) | (c << 2) | d
    +
    +#define PRAGMA(x) _Pragma(#x)
    +#define UNUSED(x) (void)(x)
    +
    +/* Compiler specific macros specific */
    +#if defined(__GNUC__)
    +#define X86_SIMD_SORT_INLINE static inline
    +#define X86_SIMD_SORT_FINLINE static inline __attribute__((always_inline))
    +#else
    +#define X86_SIMD_SORT_INLINE static
    +#define X86_SIMD_SORT_FINLINE static
    +#endif
    +
    +#if __GNUC__ >= 8
    +#define X86_SIMD_SORT_UNROLL_LOOP(num) PRAGMA(GCC unroll num)
    +#else
    +#define X86_SIMD_SORT_UNROLL_LOOP(num)
    +#endif
    +
    +typedef size_t arrsize_t;
    +
    +template 
    +struct zmm_vector;
    +
    +template 
    +struct ymm_vector;
    +
    +template 
    +struct avx2_vector;
    +
    +#endif // XSS_COMMON_INCLUDES
    diff --git a/src/java.base/linux/native/libsimdsort/xss-common-qsort.h b/src/java.base/linux/native/libsimdsort/xss-common-qsort.h
    new file mode 100644
    index 00000000000..07279a487c4
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/xss-common-qsort.h
    @@ -0,0 +1,528 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    +
    +#ifndef XSS_COMMON_QSORT
    +#define XSS_COMMON_QSORT
    +
    +/*
    + * Quicksort using AVX-512. The ideas and code are based on these two research
    + * papers [1] and [2]. On a high level, the idea is to vectorize quicksort
    + * partitioning using AVX-512 compressstore instructions. If the array size is
    + * < 128, then use Bitonic sorting network implemented on 512-bit registers.
    + * The precise network definitions depend on the dtype and are defined in
    + * separate files: avx512-16bit-qsort.hpp, avx512-32bit-qsort.hpp and
    + * avx512-64bit-qsort.hpp. Article [4] is a good resource for bitonic sorting
    + * network. The core implementations of the vectorized qsort functions
    + * avx512_qsort(T*, arrsize_t) are modified versions of avx2 quicksort
    + * presented in the paper [2] and source code associated with that paper [3].
    + *
    + * [1] Fast and Robust Vectorized In-Place Sorting of Primitive Types
    + *     https://drops.dagstuhl.de/opus/volltexte/2021/13775/
    + *
    + * [2] A Novel Hybrid Quicksort Algorithm Vectorized using AVX-512 on Intel
    + * Skylake https://arxiv.org/pdf/1704.08579.pdf
    + *
    + * [3] https://github.com/simd-sorting/fast-and-robust: SPDX-License-Identifier:
    + * MIT
    + *
    + * [4] http://mitp-content-server.mit.edu:18180/books/content/sectbyfn?collid=books_pres_0&fn=Chapter%2027.pdf&id=8030
    + *
    + */
    +
    +#include "xss-common-includes.h"
    +#include "xss-pivot-selection.hpp"
    +#include "xss-network-qsort.hpp"
    +
    +
    +template 
    +bool is_a_nan(T elem) {
    +    return std::isnan(elem);
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE T get_pivot_scalar(T *arr, const int64_t left, const int64_t right) {
    +    // median of 8 equally spaced elements
    +    int64_t NUM_ELEMENTS = 8;
    +    int64_t MID = NUM_ELEMENTS / 2;
    +    int64_t size = (right - left) / NUM_ELEMENTS;
    +    T temp[NUM_ELEMENTS];
    +    for (int64_t i = 0; i < NUM_ELEMENTS; i++) temp[i] = arr[left + (i * size)];
    +    std::sort(temp, temp + NUM_ELEMENTS);
    +    return temp[MID];
    +}
    +
    +template 
    +bool comparison_func_ge(const T &a, const T &b) {
    +    return a < b;
    +}
    +
    +template 
    +bool comparison_func_gt(const T &a, const T &b) {
    +    return a <= b;
    +}
    +
    +/*
    + * COEX == Compare and Exchange two registers by swapping min and max values
    + */
    +template 
    +X86_SIMD_SORT_INLINE void COEX(mm_t &a, mm_t &b) {
    +    mm_t temp = a;
    +    a = vtype::min(a, b);
    +    b = vtype::max(temp, b);
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE reg_t cmp_merge(reg_t in1, reg_t in2, opmask_t mask) {
    +    reg_t min = vtype::min(in2, in1);
    +    reg_t max = vtype::max(in2, in1);
    +    return vtype::mask_mov(min, mask, max);  // 0 -> min, 1 -> max
    +}
    +
    +template 
    +int avx512_double_compressstore(type_t *left_addr, type_t *right_addr,
    +                                typename vtype::opmask_t k, reg_t reg) {
    +    int amount_ge_pivot = _mm_popcnt_u32((int)k);
    +
    +    vtype::mask_compressstoreu(left_addr, vtype::knot_opmask(k), reg);
    +    vtype::mask_compressstoreu(right_addr + vtype::numlanes - amount_ge_pivot,
    +                               k, reg);
    +
    +    return amount_ge_pivot;
    +}
    +
    +// Generic function dispatches to AVX2 or AVX512 code
    +template 
    +X86_SIMD_SORT_INLINE arrsize_t partition_vec(type_t *l_store, type_t *r_store,
    +                                             const reg_t curr_vec,
    +                                             const reg_t pivot_vec,
    +                                             reg_t &smallest_vec,
    +                                             reg_t &biggest_vec, bool use_gt) {
    +    //typename vtype::opmask_t ge_mask = vtype::ge(curr_vec, pivot_vec);
    +    typename vtype::opmask_t mask;
    +    if (use_gt) mask = vtype::gt(curr_vec, pivot_vec);
    +    else mask = vtype::ge(curr_vec, pivot_vec);
    +
    +    int amount_ge_pivot =
    +        vtype::double_compressstore(l_store, r_store, mask, curr_vec);
    +
    +    smallest_vec = vtype::min(curr_vec, smallest_vec);
    +    biggest_vec = vtype::max(curr_vec, biggest_vec);
    +
    +    return amount_ge_pivot;
    +}
    +
    +/*
    + * Parition an array based on the pivot and returns the index of the
    + * first element that is greater than or equal to the pivot.
    + */
    +template 
    +X86_SIMD_SORT_INLINE arrsize_t partition_avx512(type_t *arr, arrsize_t left,
    +                                                arrsize_t right, type_t pivot,
    +                                                type_t *smallest,
    +                                                type_t *biggest,
    +                                                bool use_gt) {
    +    auto comparison_func = use_gt ? comparison_func_gt : comparison_func_ge;
    +    /* make array length divisible by vtype::numlanes , shortening the array */
    +    for (int32_t i = (right - left) % vtype::numlanes; i > 0; --i) {
    +        *smallest = std::min(*smallest, arr[left], comparison_func);
    +        *biggest = std::max(*biggest, arr[left], comparison_func);
    +        if (!comparison_func(arr[left], pivot)) {
    +            std::swap(arr[left], arr[--right]);
    +        } else {
    +            ++left;
    +        }
    +    }
    +
    +    if (left == right)
    +        return left; /* less than vtype::numlanes elements in the array */
    +
    +    using reg_t = typename vtype::reg_t;
    +    reg_t pivot_vec = vtype::set1(pivot);
    +    reg_t min_vec = vtype::set1(*smallest);
    +    reg_t max_vec = vtype::set1(*biggest);
    +
    +    if (right - left == vtype::numlanes) {
    +        reg_t vec = vtype::loadu(arr + left);
    +        arrsize_t unpartitioned = right - left - vtype::numlanes;
    +        arrsize_t l_store = left;
    +
    +        arrsize_t amount_ge_pivot =
    +            partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                                 vec, pivot_vec, min_vec, max_vec, use_gt);
    +        l_store += (vtype::numlanes - amount_ge_pivot);
    +        *smallest = vtype::reducemin(min_vec);
    +        *biggest = vtype::reducemax(max_vec);
    +        return l_store;
    +    }
    +
    +    // first and last vtype::numlanes values are partitioned at the end
    +    reg_t vec_left = vtype::loadu(arr + left);
    +    reg_t vec_right = vtype::loadu(arr + (right - vtype::numlanes));
    +    // store points of the vectors
    +    arrsize_t unpartitioned = right - left - vtype::numlanes;
    +    arrsize_t l_store = left;
    +    // indices for loading the elements
    +    left += vtype::numlanes;
    +    right -= vtype::numlanes;
    +    while (right - left != 0) {
    +        reg_t curr_vec;
    +        /*
    +         * if fewer elements are stored on the right side of the array,
    +         * then next elements are loaded from the right side,
    +         * otherwise from the left side
    +         */
    +        if ((l_store + unpartitioned + vtype::numlanes) - right <
    +            left - l_store) {
    +            right -= vtype::numlanes;
    +            curr_vec = vtype::loadu(arr + right);
    +        } else {
    +            curr_vec = vtype::loadu(arr + left);
    +            left += vtype::numlanes;
    +        }
    +        // partition the current vector and save it on both sides of the array
    +        arrsize_t amount_ge_pivot =
    +            partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                                 curr_vec, pivot_vec, min_vec, max_vec, use_gt);
    +        l_store += (vtype::numlanes - amount_ge_pivot);
    +        unpartitioned -= vtype::numlanes;
    +    }
    +
    +    /* partition and save vec_left and vec_right */
    +    arrsize_t amount_ge_pivot =
    +        partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                             vec_left, pivot_vec, min_vec, max_vec, use_gt);
    +    l_store += (vtype::numlanes - amount_ge_pivot);
    +    unpartitioned -= vtype::numlanes;
    +
    +    amount_ge_pivot =
    +        partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                             vec_right, pivot_vec, min_vec, max_vec, use_gt);
    +    l_store += (vtype::numlanes - amount_ge_pivot);
    +    unpartitioned -= vtype::numlanes;
    +
    +    *smallest = vtype::reducemin(min_vec);
    +    *biggest = vtype::reducemax(max_vec);
    +    return l_store;
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE arrsize_t
    +partition_avx512_unrolled(type_t *arr, arrsize_t left, arrsize_t right,
    +                          type_t pivot, type_t *smallest, type_t *biggest, bool use_gt) {
    +    if constexpr (num_unroll == 0) {
    +        return partition_avx512(arr, left, right, pivot, smallest,
    +                                       biggest, use_gt);
    +    }
    +
    +    /* Use regular partition_avx512 for smaller arrays */
    +    if (right - left < 3 * num_unroll * vtype::numlanes) {
    +        return partition_avx512(arr, left, right, pivot, smallest,
    +                                       biggest, use_gt);
    +    }
    +
    +    auto comparison_func = use_gt ? comparison_func_gt : comparison_func_ge;
    +    /* make array length divisible by vtype::numlanes, shortening the array */
    +    for (int32_t i = ((right - left) % (vtype::numlanes)); i > 0; --i) {
    +        *smallest = std::min(*smallest, arr[left], comparison_func);
    +        *biggest = std::max(*biggest, arr[left], comparison_func);
    +        if (!comparison_func(arr[left], pivot)) {
    +            std::swap(arr[left], arr[--right]);
    +        } else {
    +            ++left;
    +        }
    +    }
    +
    +    arrsize_t unpartitioned = right - left - vtype::numlanes;
    +    arrsize_t l_store = left;
    +
    +    using reg_t = typename vtype::reg_t;
    +    reg_t pivot_vec = vtype::set1(pivot);
    +    reg_t min_vec = vtype::set1(*smallest);
    +    reg_t max_vec = vtype::set1(*biggest);
    +
    +    /* Calculate and load more registers to make the rest of the array a
    +     * multiple of num_unroll. These registers will be partitioned at the very
    +     * end. */
    +    int vecsToPartition = ((right - left) / vtype::numlanes) % num_unroll;
    +    reg_t vec_align[num_unroll];
    +    for (int i = 0; i < vecsToPartition; i++) {
    +        vec_align[i] = vtype::loadu(arr + left + i * vtype::numlanes);
    +    }
    +    left += vecsToPartition * vtype::numlanes;
    +
    +    /* We will now have atleast 3*num_unroll registers worth of data to
    +     * process. Load left and right vtype::numlanes*num_unroll values into
    +     * registers to make space for in-place parition. The vec_left and
    +     * vec_right registers are partitioned at the end */
    +    reg_t vec_left[num_unroll], vec_right[num_unroll];
    +    X86_SIMD_SORT_UNROLL_LOOP(8)
    +    for (int ii = 0; ii < num_unroll; ++ii) {
    +        vec_left[ii] = vtype::loadu(arr + left + vtype::numlanes * ii);
    +        vec_right[ii] =
    +            vtype::loadu(arr + (right - vtype::numlanes * (num_unroll - ii)));
    +    }
    +    /* indices for loading the elements */
    +    left += num_unroll * vtype::numlanes;
    +    right -= num_unroll * vtype::numlanes;
    +    while (right - left != 0) {
    +        reg_t curr_vec[num_unroll];
    +        /*
    +         * if fewer elements are stored on the right side of the array,
    +         * then next elements are loaded from the right side,
    +         * otherwise from the left side
    +         */
    +        if ((l_store + unpartitioned + vtype::numlanes) - right <
    +            left - l_store) {
    +            right -= num_unroll * vtype::numlanes;
    +            X86_SIMD_SORT_UNROLL_LOOP(8)
    +            for (int ii = 0; ii < num_unroll; ++ii) {
    +                curr_vec[ii] = vtype::loadu(arr + right + ii * vtype::numlanes);
    +                /*
    +                 * error: '_mm_prefetch' needs target feature mmx on clang-cl
    +                 */
    +#if !(defined(_MSC_VER) && defined(__clang__))
    +                _mm_prefetch((char *)(arr + right + ii * vtype::numlanes -
    +                                      num_unroll * vtype::numlanes),
    +                             _MM_HINT_T0);
    +#endif
    +            }
    +        } else {
    +            X86_SIMD_SORT_UNROLL_LOOP(8)
    +            for (int ii = 0; ii < num_unroll; ++ii) {
    +                curr_vec[ii] = vtype::loadu(arr + left + ii * vtype::numlanes);
    +                /*
    +                 * error: '_mm_prefetch' needs target feature mmx on clang-cl
    +                 */
    +#if !(defined(_MSC_VER) && defined(__clang__))
    +                _mm_prefetch((char *)(arr + left + ii * vtype::numlanes +
    +                                      num_unroll * vtype::numlanes),
    +                             _MM_HINT_T0);
    +#endif
    +            }
    +            left += num_unroll * vtype::numlanes;
    +        }
    +        /* partition the current vector and save it on both sides of the array
    +         * */
    +        X86_SIMD_SORT_UNROLL_LOOP(8)
    +        for (int ii = 0; ii < num_unroll; ++ii) {
    +            arrsize_t amount_ge_pivot = partition_vec(
    +                arr + l_store, arr + l_store + unpartitioned, curr_vec[ii],
    +                pivot_vec, min_vec, max_vec, use_gt);
    +            l_store += (vtype::numlanes - amount_ge_pivot);
    +            unpartitioned -= vtype::numlanes;
    +        }
    +    }
    +
    +    /* partition and save vec_left[num_unroll] and vec_right[num_unroll] */
    +    X86_SIMD_SORT_UNROLL_LOOP(8)
    +    for (int ii = 0; ii < num_unroll; ++ii) {
    +        arrsize_t amount_ge_pivot =
    +            partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                                 vec_left[ii], pivot_vec, min_vec, max_vec, use_gt);
    +        l_store += (vtype::numlanes - amount_ge_pivot);
    +        unpartitioned -= vtype::numlanes;
    +    }
    +    X86_SIMD_SORT_UNROLL_LOOP(8)
    +    for (int ii = 0; ii < num_unroll; ++ii) {
    +        arrsize_t amount_ge_pivot =
    +            partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                                 vec_right[ii], pivot_vec, min_vec, max_vec, use_gt);
    +        l_store += (vtype::numlanes - amount_ge_pivot);
    +        unpartitioned -= vtype::numlanes;
    +    }
    +
    +    /* partition and save vec_align[vecsToPartition] */
    +    X86_SIMD_SORT_UNROLL_LOOP(8)
    +    for (int ii = 0; ii < vecsToPartition; ++ii) {
    +        arrsize_t amount_ge_pivot =
    +            partition_vec(arr + l_store, arr + l_store + unpartitioned,
    +                                 vec_align[ii], pivot_vec, min_vec, max_vec, use_gt);
    +        l_store += (vtype::numlanes - amount_ge_pivot);
    +        unpartitioned -= vtype::numlanes;
    +    }
    +
    +    *smallest = vtype::reducemin(min_vec);
    +    *biggest = vtype::reducemax(max_vec);
    +    return l_store;
    +}
    +
    +template 
    +void sort_n(typename vtype::type_t *arr, int N);
    +
    +template 
    +static void qsort_(type_t *arr, arrsize_t left, arrsize_t right,
    +                   arrsize_t max_iters) {
    +    /*
    +     * Resort to std::sort if quicksort isnt making any progress
    +     */
    +    if (max_iters <= 0) {
    +        std::sort(arr + left, arr + right + 1, comparison_func_ge);
    +        return;
    +    }
    +    /*
    +     * Base case: use bitonic networks to sort arrays <=
    +     * vtype::network_sort_threshold
    +     */
    +    if (right + 1 - left <= vtype::network_sort_threshold) {
    +        sort_n(
    +            arr + left, (int32_t)(right + 1 - left));
    +        return;
    +    }
    +
    +    type_t pivot = get_pivot_blocks(arr, left, right);
    +    type_t smallest = vtype::type_max();
    +    type_t biggest = vtype::type_min();
    +
    +    arrsize_t pivot_index =
    +        partition_avx512_unrolled(
    +            arr, left, right + 1, pivot, &smallest, &biggest, false);
    +
    +    if (pivot != smallest)
    +        qsort_(arr, left, pivot_index - 1, max_iters - 1);
    +    if (pivot != biggest) qsort_(arr, pivot_index, right, max_iters - 1);
    +}
    +
    +// Hooks for OpenJDK sort
    +// to_index (exclusive)
    +template 
    +static int64_t vectorized_partition(type_t *arr, int64_t from_index, int64_t to_index, type_t pivot, bool use_gt) {
    +    type_t smallest = vtype::type_max();
    +    type_t biggest = vtype::type_min();
    +    int64_t pivot_index = partition_avx512_unrolled(
    +            arr, from_index, to_index, pivot, &smallest, &biggest, use_gt);
    +    return pivot_index;
    +}
    +
    +// partitioning functions
    +template 
    +X86_SIMD_SORT_INLINE void simd_dual_pivot_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2){
    +    const T pivot1 = arr[index_pivot1];
    +    const T pivot2 = arr[index_pivot2];
    +
    +    const int64_t low = from_index;
    +    const int64_t high = to_index;
    +    const int64_t start = low + 1;
    +    const int64_t end = high - 1;
    +
    +
    +    std::swap(arr[index_pivot1], arr[low]);
    +    std::swap(arr[index_pivot2], arr[end]);
    +
    +
    +    const int64_t pivot_index2 = vectorized_partition(arr, start, end, pivot2, true); // use_gt = true
    +    std::swap(arr[end], arr[pivot_index2]);
    +    int64_t upper = pivot_index2;
    +
    +    // if all other elements are greater than pivot2 (and pivot1), no need to do further partitioning
    +    if (upper == start) {
    +        pivot_indices[0] = low;
    +        pivot_indices[1] = upper;
    +        return;
    +    }
    +
    +    const int64_t pivot_index1 = vectorized_partition(arr, start, upper, pivot1, false); // use_ge (use_gt = false)
    +    int64_t lower = pivot_index1 - 1;
    +    std::swap(arr[low], arr[lower]);
    +
    +    pivot_indices[0] = lower;
    +    pivot_indices[1] = upper;
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE void simd_single_pivot_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot) {
    +    const T pivot = arr[index_pivot];
    +
    +    const int64_t low = from_index;
    +    const int64_t high = to_index;
    +    const int64_t end = high - 1;
    +
    +
    +    const int64_t pivot_index1 = vectorized_partition(arr, low, high, pivot, false); // use_gt = false (use_ge)
    +    int64_t lower = pivot_index1;
    +
    +    const int64_t pivot_index2 = vectorized_partition(arr, pivot_index1, high, pivot, true); // use_gt = true
    +    int64_t upper = pivot_index2;
    +
    +    pivot_indices[0] = lower;
    +    pivot_indices[1] = upper;
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE void simd_fast_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2) {
    +    if (index_pivot1 != index_pivot2) {
    +        simd_dual_pivot_partition(arr, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
    +    }
    +    else {
    +        simd_single_pivot_partition(arr, from_index, to_index, pivot_indices, index_pivot1);
    +    }
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE void insertion_sort(T *arr, int32_t from_index, int32_t to_index) {
    +    for (int i, k = from_index; ++k < to_index; ) {
    +        T ai = arr[i = k];
    +        if (ai < arr[i - 1]) {
    +            while (--i >= from_index && ai < arr[i]) {
    +                arr[i + 1] = arr[i];
    +            }
    +            arr[i + 1] = ai;
    +        }
    +    }
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE void simd_fast_sort(T *arr, arrsize_t from_index, arrsize_t to_index, const arrsize_t INS_SORT_THRESHOLD)
    +{
    +    arrsize_t arrsize = to_index - from_index;
    +    if (arrsize <= INS_SORT_THRESHOLD) {
    +        insertion_sort(arr, from_index, to_index);
    +    } else {
    +        qsort_(arr, from_index, to_index - 1, 2 * (arrsize_t)log2(arrsize));
    +    }
    +}
    +
    +#define DEFINE_METHODS(ISA, VTYPE) \
    +    template  \
    +    X86_SIMD_SORT_INLINE void ISA##_fast_sort( \
    +            T *arr, arrsize_t from_index, arrsize_t to_index, const arrsize_t INS_SORT_THRESHOLD) \
    +    { \
    +        simd_fast_sort(arr, from_index, to_index, INS_SORT_THRESHOLD); \
    +    } \
    +    template  \
    +    X86_SIMD_SORT_INLINE void ISA##_fast_partition( \
    +            T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2) \
    +    { \
    +        simd_fast_partition(arr, from_index, to_index, pivot_indices, index_pivot1, index_pivot2); \
    +    }
    +
    +DEFINE_METHODS(avx2, avx2_vector)
    +DEFINE_METHODS(avx512, zmm_vector)
    +
    +#endif  // XSS_COMMON_QSORT
    diff --git a/src/java.base/linux/native/libsimdsort/xss-network-qsort.hpp b/src/java.base/linux/native/libsimdsort/xss-network-qsort.hpp
    new file mode 100644
    index 00000000000..d0a6188b63b
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/xss-network-qsort.hpp
    @@ -0,0 +1,209 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    +
    +#ifndef XSS_NETWORK_QSORT
    +#define XSS_NETWORK_QSORT
    +
    +#include "xss-common-qsort.h"
    +#include "xss-optimal-networks.hpp"
    +
    +template 
    +X86_SIMD_SORT_FINLINE void bitonic_sort_n_vec(reg_t *regs) {
    +    if constexpr (numVecs == 1) {
    +        UNUSED(regs);
    +        return;
    +    } else if constexpr (numVecs == 2) {
    +        COEX(regs[0], regs[1]);
    +    } else if constexpr (numVecs == 4) {
    +        optimal_sort_4(regs);
    +    } else if constexpr (numVecs == 8) {
    +        optimal_sort_8(regs);
    +    } else if constexpr (numVecs == 16) {
    +        optimal_sort_16(regs);
    +    } else if constexpr (numVecs == 32) {
    +        optimal_sort_32(regs);
    +    } else {
    +        static_assert(numVecs == -1, "should not reach here");
    +    }
    +}
    +
    +/*
    + * Swizzle ops explained:
    + * swap_n: swap neighbouring blocks of size  within block of
    + * size  reg i        = [7,6,5,4,3,2,1,0] swap_n<2>:   =
    + * [[6,7],[4,5],[2,3],[0,1]] swap_n<4>:   = [[5,4,7,6],[1,0,3,2]] swap_n<8>:   =
    + * [[3,2,1,0,7,6,5,4]] reverse_n: reverse elements within block of size
    + *  reg i        = [7,6,5,4,3,2,1,0] rev_n<2>:    =
    + * [[6,7],[4,5],[2,3],[0,1]] rev_n<4>:    = [[4,5,6,7],[0,1,2,3]] rev_n<8>:    =
    + * [[0,1,2,3,4,5,6,7]] merge_n: merge blocks of  elements from
    + * two regs reg b,a      = [a,a,a,a,a,a,a,a], [b,b,b,b,b,b,b,b] merge_n<2>   =
    + * [a,b,a,b,a,b,a,b] merge_n<4>   = [a,a,b,b,a,a,b,b] merge_n<8>   =
    + * [a,a,a,a,b,b,b,b]
    + */
    +
    +template 
    +X86_SIMD_SORT_FINLINE void internal_merge_n_vec(typename vtype::reg_t *reg) {
    +    using reg_t = typename vtype::reg_t;
    +    using swizzle = typename vtype::swizzle_ops;
    +    if constexpr (scale <= 1) {
    +        UNUSED(reg);
    +        return;
    +    } else {
    +        if constexpr (first) {
    +            // Use reverse then merge
    +            X86_SIMD_SORT_UNROLL_LOOP(64)
    +            for (int i = 0; i < numVecs; i++) {
    +                reg_t &v = reg[i];
    +                reg_t rev = swizzle::template reverse_n(v);
    +                COEX(rev, v);
    +                v = swizzle::template merge_n(v, rev);
    +            }
    +        } else {
    +            // Use swap then merge
    +            X86_SIMD_SORT_UNROLL_LOOP(64)
    +            for (int i = 0; i < numVecs; i++) {
    +                reg_t &v = reg[i];
    +                reg_t swap = swizzle::template swap_n(v);
    +                COEX(swap, v);
    +                v = swizzle::template merge_n(v, swap);
    +            }
    +        }
    +        internal_merge_n_vec(reg);
    +    }
    +}
    +
    +template 
    +X86_SIMD_SORT_FINLINE void merge_substep_n_vec(reg_t *regs) {
    +    using swizzle = typename vtype::swizzle_ops;
    +    if constexpr (numVecs <= 1) {
    +        UNUSED(regs);
    +        return;
    +    }
    +
    +    // Reverse upper half of vectors
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = numVecs / 2; i < numVecs; i++) {
    +        regs[i] = swizzle::template reverse_n(regs[i]);
    +    }
    +    // Do compare exchanges
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = 0; i < numVecs / 2; i++) {
    +        COEX(regs[i], regs[numVecs - 1 - i]);
    +    }
    +
    +    merge_substep_n_vec(regs);
    +    merge_substep_n_vec(regs + numVecs / 2);
    +}
    +
    +template 
    +X86_SIMD_SORT_FINLINE void merge_step_n_vec(reg_t *regs) {
    +    // Do cross vector merges
    +    merge_substep_n_vec(regs);
    +
    +    // Do internal vector merges
    +    internal_merge_n_vec(regs);
    +}
    +
    +template 
    +X86_SIMD_SORT_FINLINE void merge_n_vec(reg_t *regs) {
    +    if constexpr (numPer > vtype::numlanes) {
    +        UNUSED(regs);
    +        return;
    +    } else {
    +        merge_step_n_vec(regs);
    +        merge_n_vec(regs);
    +    }
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE void sort_n_vec(typename vtype::type_t *arr, int N) {
    +    static_assert(numVecs > 0, "numVecs should be > 0");
    +    if constexpr (numVecs > 1) {
    +        if (N * 2 <= numVecs * vtype::numlanes) {
    +            sort_n_vec(arr, N);
    +            return;
    +        }
    +    }
    +
    +    reg_t vecs[numVecs];
    +
    +    // Generate masks for loading and storing
    +    typename vtype::opmask_t ioMasks[numVecs - numVecs / 2];
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = numVecs / 2, j = 0; i < numVecs; i++, j++) {
    +        uint64_t num_to_read =
    +            std::min((uint64_t)std::max(0, N - i * vtype::numlanes),
    +                     (uint64_t)vtype::numlanes);
    +        ioMasks[j] = vtype::get_partial_loadmask(num_to_read);
    +    }
    +
    +    // Unmasked part of the load
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = 0; i < numVecs / 2; i++) {
    +        vecs[i] = vtype::loadu(arr + i * vtype::numlanes);
    +    }
    +    // Masked part of the load
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = numVecs / 2, j = 0; i < numVecs; i++, j++) {
    +        vecs[i] = vtype::mask_loadu(vtype::zmm_max(), ioMasks[j],
    +                                    arr + i * vtype::numlanes);
    +    }
    +
    +    /* Run the initial sorting network to sort the columns of the [numVecs x
    +     * num_lanes] matrix
    +     */
    +    bitonic_sort_n_vec(vecs);
    +
    +    // Merge the vectors using bitonic merging networks
    +    merge_n_vec(vecs);
    +
    +    // Unmasked part of the store
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = 0; i < numVecs / 2; i++) {
    +        vtype::storeu(arr + i * vtype::numlanes, vecs[i]);
    +    }
    +    // Masked part of the store
    +    X86_SIMD_SORT_UNROLL_LOOP(64)
    +    for (int i = numVecs / 2, j = 0; i < numVecs; i++, j++) {
    +        vtype::mask_storeu(arr + i * vtype::numlanes, ioMasks[j], vecs[i]);
    +    }
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE void sort_n(typename vtype::type_t *arr, int N) {
    +    constexpr int numVecs = maxN / vtype::numlanes;
    +    constexpr bool isMultiple = (maxN == (vtype::numlanes * numVecs));
    +    constexpr bool powerOfTwo = (numVecs != 0 && !(numVecs & (numVecs - 1)));
    +    static_assert(powerOfTwo == true && isMultiple == true,
    +                  "maxN must be vtype::numlanes times a power of 2");
    +
    +    sort_n_vec(arr, N);
    +}
    +#endif
    diff --git a/src/java.base/linux/native/libsimdsort/xss-optimal-networks.hpp b/src/java.base/linux/native/libsimdsort/xss-optimal-networks.hpp
    new file mode 100644
    index 00000000000..584b8c84118
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/xss-optimal-networks.hpp
    @@ -0,0 +1,342 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort) All of these sources
    +// files are generated from the optimal networks described in
    +// https://bertdobbelaere.github.io/sorting_networks.html
    +
    +template 
    +X86_SIMD_SORT_FINLINE void optimal_sort_4(reg_t *vecs) {
    +    COEX(vecs[0], vecs[2]);
    +    COEX(vecs[1], vecs[3]);
    +
    +    COEX(vecs[0], vecs[1]);
    +    COEX(vecs[2], vecs[3]);
    +
    +    COEX(vecs[1], vecs[2]);
    +}
    +
    +template 
    +X86_SIMD_SORT_FINLINE void optimal_sort_8(reg_t *vecs) {
    +    COEX(vecs[0], vecs[2]);
    +    COEX(vecs[1], vecs[3]);
    +    COEX(vecs[4], vecs[6]);
    +    COEX(vecs[5], vecs[7]);
    +
    +    COEX(vecs[0], vecs[4]);
    +    COEX(vecs[1], vecs[5]);
    +    COEX(vecs[2], vecs[6]);
    +    COEX(vecs[3], vecs[7]);
    +
    +    COEX(vecs[0], vecs[1]);
    +    COEX(vecs[2], vecs[3]);
    +    COEX(vecs[4], vecs[5]);
    +    COEX(vecs[6], vecs[7]);
    +
    +    COEX(vecs[2], vecs[4]);
    +    COEX(vecs[3], vecs[5]);
    +
    +    COEX(vecs[1], vecs[4]);
    +    COEX(vecs[3], vecs[6]);
    +
    +    COEX(vecs[1], vecs[2]);
    +    COEX(vecs[3], vecs[4]);
    +    COEX(vecs[5], vecs[6]);
    +}
    +
    +template 
    +X86_SIMD_SORT_FINLINE void optimal_sort_16(reg_t *vecs) {
    +    COEX(vecs[0], vecs[13]);
    +    COEX(vecs[1], vecs[12]);
    +    COEX(vecs[2], vecs[15]);
    +    COEX(vecs[3], vecs[14]);
    +    COEX(vecs[4], vecs[8]);
    +    COEX(vecs[5], vecs[6]);
    +    COEX(vecs[7], vecs[11]);
    +    COEX(vecs[9], vecs[10]);
    +
    +    COEX(vecs[0], vecs[5]);
    +    COEX(vecs[1], vecs[7]);
    +    COEX(vecs[2], vecs[9]);
    +    COEX(vecs[3], vecs[4]);
    +    COEX(vecs[6], vecs[13]);
    +    COEX(vecs[8], vecs[14]);
    +    COEX(vecs[10], vecs[15]);
    +    COEX(vecs[11], vecs[12]);
    +
    +    COEX(vecs[0], vecs[1]);
    +    COEX(vecs[2], vecs[3]);
    +    COEX(vecs[4], vecs[5]);
    +    COEX(vecs[6], vecs[8]);
    +    COEX(vecs[7], vecs[9]);
    +    COEX(vecs[10], vecs[11]);
    +    COEX(vecs[12], vecs[13]);
    +    COEX(vecs[14], vecs[15]);
    +
    +    COEX(vecs[0], vecs[2]);
    +    COEX(vecs[1], vecs[3]);
    +    COEX(vecs[4], vecs[10]);
    +    COEX(vecs[5], vecs[11]);
    +    COEX(vecs[6], vecs[7]);
    +    COEX(vecs[8], vecs[9]);
    +    COEX(vecs[12], vecs[14]);
    +    COEX(vecs[13], vecs[15]);
    +
    +    COEX(vecs[1], vecs[2]);
    +    COEX(vecs[3], vecs[12]);
    +    COEX(vecs[4], vecs[6]);
    +    COEX(vecs[5], vecs[7]);
    +    COEX(vecs[8], vecs[10]);
    +    COEX(vecs[9], vecs[11]);
    +    COEX(vecs[13], vecs[14]);
    +
    +    COEX(vecs[1], vecs[4]);
    +    COEX(vecs[2], vecs[6]);
    +    COEX(vecs[5], vecs[8]);
    +    COEX(vecs[7], vecs[10]);
    +    COEX(vecs[9], vecs[13]);
    +    COEX(vecs[11], vecs[14]);
    +
    +    COEX(vecs[2], vecs[4]);
    +    COEX(vecs[3], vecs[6]);
    +    COEX(vecs[9], vecs[12]);
    +    COEX(vecs[11], vecs[13]);
    +
    +    COEX(vecs[3], vecs[5]);
    +    COEX(vecs[6], vecs[8]);
    +    COEX(vecs[7], vecs[9]);
    +    COEX(vecs[10], vecs[12]);
    +
    +    COEX(vecs[3], vecs[4]);
    +    COEX(vecs[5], vecs[6]);
    +    COEX(vecs[7], vecs[8]);
    +    COEX(vecs[9], vecs[10]);
    +    COEX(vecs[11], vecs[12]);
    +
    +    COEX(vecs[6], vecs[7]);
    +    COEX(vecs[8], vecs[9]);
    +}
    +
    +template 
    +X86_SIMD_SORT_FINLINE void optimal_sort_32(reg_t *vecs) {
    +    COEX(vecs[0], vecs[1]);
    +    COEX(vecs[2], vecs[3]);
    +    COEX(vecs[4], vecs[5]);
    +    COEX(vecs[6], vecs[7]);
    +    COEX(vecs[8], vecs[9]);
    +    COEX(vecs[10], vecs[11]);
    +    COEX(vecs[12], vecs[13]);
    +    COEX(vecs[14], vecs[15]);
    +    COEX(vecs[16], vecs[17]);
    +    COEX(vecs[18], vecs[19]);
    +    COEX(vecs[20], vecs[21]);
    +    COEX(vecs[22], vecs[23]);
    +    COEX(vecs[24], vecs[25]);
    +    COEX(vecs[26], vecs[27]);
    +    COEX(vecs[28], vecs[29]);
    +    COEX(vecs[30], vecs[31]);
    +
    +    COEX(vecs[0], vecs[2]);
    +    COEX(vecs[1], vecs[3]);
    +    COEX(vecs[4], vecs[6]);
    +    COEX(vecs[5], vecs[7]);
    +    COEX(vecs[8], vecs[10]);
    +    COEX(vecs[9], vecs[11]);
    +    COEX(vecs[12], vecs[14]);
    +    COEX(vecs[13], vecs[15]);
    +    COEX(vecs[16], vecs[18]);
    +    COEX(vecs[17], vecs[19]);
    +    COEX(vecs[20], vecs[22]);
    +    COEX(vecs[21], vecs[23]);
    +    COEX(vecs[24], vecs[26]);
    +    COEX(vecs[25], vecs[27]);
    +    COEX(vecs[28], vecs[30]);
    +    COEX(vecs[29], vecs[31]);
    +
    +    COEX(vecs[0], vecs[4]);
    +    COEX(vecs[1], vecs[5]);
    +    COEX(vecs[2], vecs[6]);
    +    COEX(vecs[3], vecs[7]);
    +    COEX(vecs[8], vecs[12]);
    +    COEX(vecs[9], vecs[13]);
    +    COEX(vecs[10], vecs[14]);
    +    COEX(vecs[11], vecs[15]);
    +    COEX(vecs[16], vecs[20]);
    +    COEX(vecs[17], vecs[21]);
    +    COEX(vecs[18], vecs[22]);
    +    COEX(vecs[19], vecs[23]);
    +    COEX(vecs[24], vecs[28]);
    +    COEX(vecs[25], vecs[29]);
    +    COEX(vecs[26], vecs[30]);
    +    COEX(vecs[27], vecs[31]);
    +
    +    COEX(vecs[0], vecs[8]);
    +    COEX(vecs[1], vecs[9]);
    +    COEX(vecs[2], vecs[10]);
    +    COEX(vecs[3], vecs[11]);
    +    COEX(vecs[4], vecs[12]);
    +    COEX(vecs[5], vecs[13]);
    +    COEX(vecs[6], vecs[14]);
    +    COEX(vecs[7], vecs[15]);
    +    COEX(vecs[16], vecs[24]);
    +    COEX(vecs[17], vecs[25]);
    +    COEX(vecs[18], vecs[26]);
    +    COEX(vecs[19], vecs[27]);
    +    COEX(vecs[20], vecs[28]);
    +    COEX(vecs[21], vecs[29]);
    +    COEX(vecs[22], vecs[30]);
    +    COEX(vecs[23], vecs[31]);
    +
    +    COEX(vecs[0], vecs[16]);
    +    COEX(vecs[1], vecs[8]);
    +    COEX(vecs[2], vecs[4]);
    +    COEX(vecs[3], vecs[12]);
    +    COEX(vecs[5], vecs[10]);
    +    COEX(vecs[6], vecs[9]);
    +    COEX(vecs[7], vecs[14]);
    +    COEX(vecs[11], vecs[13]);
    +    COEX(vecs[15], vecs[31]);
    +    COEX(vecs[17], vecs[24]);
    +    COEX(vecs[18], vecs[20]);
    +    COEX(vecs[19], vecs[28]);
    +    COEX(vecs[21], vecs[26]);
    +    COEX(vecs[22], vecs[25]);
    +    COEX(vecs[23], vecs[30]);
    +    COEX(vecs[27], vecs[29]);
    +
    +    COEX(vecs[1], vecs[2]);
    +    COEX(vecs[3], vecs[5]);
    +    COEX(vecs[4], vecs[8]);
    +    COEX(vecs[6], vecs[22]);
    +    COEX(vecs[7], vecs[11]);
    +    COEX(vecs[9], vecs[25]);
    +    COEX(vecs[10], vecs[12]);
    +    COEX(vecs[13], vecs[14]);
    +    COEX(vecs[17], vecs[18]);
    +    COEX(vecs[19], vecs[21]);
    +    COEX(vecs[20], vecs[24]);
    +    COEX(vecs[23], vecs[27]);
    +    COEX(vecs[26], vecs[28]);
    +    COEX(vecs[29], vecs[30]);
    +
    +    COEX(vecs[1], vecs[17]);
    +    COEX(vecs[2], vecs[18]);
    +    COEX(vecs[3], vecs[19]);
    +    COEX(vecs[4], vecs[20]);
    +    COEX(vecs[5], vecs[10]);
    +    COEX(vecs[7], vecs[23]);
    +    COEX(vecs[8], vecs[24]);
    +    COEX(vecs[11], vecs[27]);
    +    COEX(vecs[12], vecs[28]);
    +    COEX(vecs[13], vecs[29]);
    +    COEX(vecs[14], vecs[30]);
    +    COEX(vecs[21], vecs[26]);
    +
    +    COEX(vecs[3], vecs[17]);
    +    COEX(vecs[4], vecs[16]);
    +    COEX(vecs[5], vecs[21]);
    +    COEX(vecs[6], vecs[18]);
    +    COEX(vecs[7], vecs[9]);
    +    COEX(vecs[8], vecs[20]);
    +    COEX(vecs[10], vecs[26]);
    +    COEX(vecs[11], vecs[23]);
    +    COEX(vecs[13], vecs[25]);
    +    COEX(vecs[14], vecs[28]);
    +    COEX(vecs[15], vecs[27]);
    +    COEX(vecs[22], vecs[24]);
    +
    +    COEX(vecs[1], vecs[4]);
    +    COEX(vecs[3], vecs[8]);
    +    COEX(vecs[5], vecs[16]);
    +    COEX(vecs[7], vecs[17]);
    +    COEX(vecs[9], vecs[21]);
    +    COEX(vecs[10], vecs[22]);
    +    COEX(vecs[11], vecs[19]);
    +    COEX(vecs[12], vecs[20]);
    +    COEX(vecs[14], vecs[24]);
    +    COEX(vecs[15], vecs[26]);
    +    COEX(vecs[23], vecs[28]);
    +    COEX(vecs[27], vecs[30]);
    +
    +    COEX(vecs[2], vecs[5]);
    +    COEX(vecs[7], vecs[8]);
    +    COEX(vecs[9], vecs[18]);
    +    COEX(vecs[11], vecs[17]);
    +    COEX(vecs[12], vecs[16]);
    +    COEX(vecs[13], vecs[22]);
    +    COEX(vecs[14], vecs[20]);
    +    COEX(vecs[15], vecs[19]);
    +    COEX(vecs[23], vecs[24]);
    +    COEX(vecs[26], vecs[29]);
    +
    +    COEX(vecs[2], vecs[4]);
    +    COEX(vecs[6], vecs[12]);
    +    COEX(vecs[9], vecs[16]);
    +    COEX(vecs[10], vecs[11]);
    +    COEX(vecs[13], vecs[17]);
    +    COEX(vecs[14], vecs[18]);
    +    COEX(vecs[15], vecs[22]);
    +    COEX(vecs[19], vecs[25]);
    +    COEX(vecs[20], vecs[21]);
    +    COEX(vecs[27], vecs[29]);
    +
    +    COEX(vecs[5], vecs[6]);
    +    COEX(vecs[8], vecs[12]);
    +    COEX(vecs[9], vecs[10]);
    +    COEX(vecs[11], vecs[13]);
    +    COEX(vecs[14], vecs[16]);
    +    COEX(vecs[15], vecs[17]);
    +    COEX(vecs[18], vecs[20]);
    +    COEX(vecs[19], vecs[23]);
    +    COEX(vecs[21], vecs[22]);
    +    COEX(vecs[25], vecs[26]);
    +
    +    COEX(vecs[3], vecs[5]);
    +    COEX(vecs[6], vecs[7]);
    +    COEX(vecs[8], vecs[9]);
    +    COEX(vecs[10], vecs[12]);
    +    COEX(vecs[11], vecs[14]);
    +    COEX(vecs[13], vecs[16]);
    +    COEX(vecs[15], vecs[18]);
    +    COEX(vecs[17], vecs[20]);
    +    COEX(vecs[19], vecs[21]);
    +    COEX(vecs[22], vecs[23]);
    +    COEX(vecs[24], vecs[25]);
    +    COEX(vecs[26], vecs[28]);
    +
    +    COEX(vecs[3], vecs[4]);
    +    COEX(vecs[5], vecs[6]);
    +    COEX(vecs[7], vecs[8]);
    +    COEX(vecs[9], vecs[10]);
    +    COEX(vecs[11], vecs[12]);
    +    COEX(vecs[13], vecs[14]);
    +    COEX(vecs[15], vecs[16]);
    +    COEX(vecs[17], vecs[18]);
    +    COEX(vecs[19], vecs[20]);
    +    COEX(vecs[21], vecs[22]);
    +    COEX(vecs[23], vecs[24]);
    +    COEX(vecs[25], vecs[26]);
    +    COEX(vecs[27], vecs[28]);
    +}
    diff --git a/src/java.base/linux/native/libsimdsort/xss-pivot-selection.hpp b/src/java.base/linux/native/libsimdsort/xss-pivot-selection.hpp
    new file mode 100644
    index 00000000000..d65a30b56d6
    --- /dev/null
    +++ b/src/java.base/linux/native/libsimdsort/xss-pivot-selection.hpp
    @@ -0,0 +1,88 @@
    +/*
    + * Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
    + * Copyright (c) 2021 Serge Sans Paille. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
    +
    +template 
    +X86_SIMD_SORT_INLINE void COEX(mm_t &a, mm_t &b);
    +
    +template 
    +X86_SIMD_SORT_INLINE type_t get_pivot(type_t *arr, const arrsize_t left,
    +                                      const arrsize_t right) {
    +    using reg_t = typename vtype::reg_t;
    +    type_t samples[vtype::numlanes];
    +    arrsize_t delta = (right - left) / vtype::numlanes;
    +    for (int i = 0; i < vtype::numlanes; i++) {
    +        samples[i] = arr[left + i * delta];
    +    }
    +    reg_t rand_vec = vtype::loadu(samples);
    +    reg_t sort = vtype::sort_vec(rand_vec);
    +
    +    return ((type_t *)&sort)[vtype::numlanes / 2];
    +}
    +
    +template 
    +X86_SIMD_SORT_INLINE type_t get_pivot_blocks(type_t *arr, const arrsize_t left,
    +                                             const arrsize_t right) {
    +    if (right - left <= 1024) {
    +        return get_pivot(arr, left, right);
    +    }
    +
    +    using reg_t = typename vtype::reg_t;
    +    constexpr int numVecs = 5;
    +
    +    arrsize_t width = (right - vtype::numlanes) - left;
    +    arrsize_t delta = width / numVecs;
    +
    +    reg_t vecs[numVecs];
    +    // Load data
    +    for (int i = 0; i < numVecs; i++) {
    +        vecs[i] = vtype::loadu(arr + left + delta * i);
    +    }
    +
    +    // Implement sorting network (from
    +    // https://bertdobbelaere.github.io/sorting_networks.html)
    +    COEX(vecs[0], vecs[3]);
    +    COEX(vecs[1], vecs[4]);
    +
    +    COEX(vecs[0], vecs[2]);
    +    COEX(vecs[1], vecs[3]);
    +
    +    COEX(vecs[0], vecs[1]);
    +    COEX(vecs[2], vecs[4]);
    +
    +    COEX(vecs[1], vecs[2]);
    +    COEX(vecs[3], vecs[4]);
    +
    +    COEX(vecs[2], vecs[3]);
    +
    +    // Calculate median of the middle vector
    +    reg_t &vec = vecs[numVecs / 2];
    +    vec = vtype::sort_vec(vec);
    +
    +    type_t data[vtype::numlanes];
    +    vtype::storeu(data, vec);
    +    return data[vtype::numlanes / 2];
    +}
    diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java
    index 17f82b2eacc..ff7e1f4ddd5 100644
    --- a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java
    +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -85,7 +85,7 @@ final class DESKey implements SecretKey {
             // Use the cleaner to zero the key when no longer referenced
             final byte[] k = this.key;
             CleanerFactory.cleaner().register(this,
    -                () -> java.util.Arrays.fill(k, (byte)0x00));
    +                () -> Arrays.fill(k, (byte)0x00));
         }
     
         public byte[] getEncoded() {
    @@ -136,7 +136,7 @@ public boolean equals(Object obj) {
     
                 byte[] thatKey = that.getEncoded();
                 boolean ret = MessageDigest.isEqual(this.key, thatKey);
    -            java.util.Arrays.fill(thatKey, (byte)0x00);
    +            Arrays.fill(thatKey, (byte)0x00);
                 return ret;
             } finally {
                 // prevent this from being cleaned for the above block
    @@ -168,7 +168,7 @@ private void readObject(java.io.ObjectInputStream s)
             // Use the cleaner to zero the key when no longer referenced
             final byte[] k = this.key;
             CleanerFactory.cleaner().register(this,
    -                () -> java.util.Arrays.fill(k, (byte)0x00));
    +                () -> Arrays.fill(k, (byte)0x00));
         }
     
         /**
    diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java
    index f5c3d8384df..53f72499a33 100644
    --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java
    +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -87,7 +87,7 @@ final class DESedeKey implements SecretKey {
             // Use the cleaner to zero the key when no longer referenced
             final byte[] k = this.key;
             CleanerFactory.cleaner().register(this,
    -                () -> java.util.Arrays.fill(k, (byte)0x00));
    +                () -> Arrays.fill(k, (byte)0x00));
         }
     
         public byte[] getEncoded() {
    @@ -137,7 +137,7 @@ public boolean equals(Object obj) {
     
                 byte[] thatKey = that.getEncoded();
                 boolean ret = MessageDigest.isEqual(this.key, thatKey);
    -            java.util.Arrays.fill(thatKey, (byte)0x00);
    +            Arrays.fill(thatKey, (byte)0x00);
                 return ret;
             } finally {
                 // prevent this from being cleaned for the above block
    @@ -162,7 +162,7 @@ private void readObject(java.io.ObjectInputStream s)
             }
             byte[] temp = key;
             this.key = temp.clone();
    -        java.util.Arrays.fill(temp, (byte)0x00);
    +        Arrays.fill(temp, (byte)0x00);
     
             DESKeyGenerator.setParityBit(key, 0);
             DESKeyGenerator.setParityBit(key, 8);
    @@ -171,7 +171,7 @@ private void readObject(java.io.ObjectInputStream s)
             // Use the cleaner to zero the key when no longer referenced
             final byte[] k = this.key;
             CleanerFactory.cleaner().register(this,
    -                () -> java.util.Arrays.fill(k, (byte)0x00));
    +                () -> Arrays.fill(k, (byte)0x00));
         }
     
         /**
    diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java b/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java
    index 902d302cac4..a86f313e2c9 100644
    --- a/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java
    +++ b/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java
    @@ -74,7 +74,6 @@ public void padWithLen(byte[] in, int off, int len)
             SunJCE.getRandom().nextBytes(padding);
             System.arraycopy(padding, 0, in, off, len - 1);
             in[idx - 1] = paddingOctet;
    -        return;
         }
     
         /**
    diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java
    index 480a0810425..21dc463572e 100644
    --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java
    +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java
    @@ -84,7 +84,7 @@ final class PBEKey implements SecretKey {
             // Use the cleaner to zero the key when no longer referenced
             final byte[] k = this.key;
             cleanable = CleanerFactory.cleaner().register(this,
    -                () -> java.util.Arrays.fill(k, (byte)0x00));
    +                () -> Arrays.fill(k, (byte)0x00));
         }
     
         public byte[] getEncoded() {
    @@ -196,7 +196,7 @@ private void readObject(java.io.ObjectInputStream s)
             // Use cleaner to zero the key when no longer referenced
             final byte[] k = this.key;
             cleanable = CleanerFactory.cleaner().register(this,
    -                () -> java.util.Arrays.fill(k, (byte)0x00));
    +                () -> Arrays.fill(k, (byte)0x00));
         }
     
     
    diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java b/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java
    index 7b3850bd556..af072c6f5d7 100644
    --- a/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java
    +++ b/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java
    @@ -71,7 +71,6 @@ public void padWithLen(byte[] in, int off, int len)
     
             byte paddingOctet = (byte) (len & 0xff);
             Arrays.fill(in, off, idx, paddingOctet);
    -        return;
         }
     
         /**
    diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java
    index e5a44761b8a..d4531d27db1 100644
    --- a/src/java.base/share/classes/java/io/BufferedInputStream.java
    +++ b/src/java.base/share/classes/java/io/BufferedInputStream.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -643,9 +643,13 @@ private long implTransferTo(OutputStream out) throws IOException {
             if (getClass() == BufferedInputStream.class && markpos == -1) {
                 int avail = count - pos;
                 if (avail > 0) {
    -                // Prevent poisoning and leaking of buf
    -                byte[] buffer = Arrays.copyOfRange(getBufIfOpen(), pos, count);
    -                out.write(buffer);
    +                if (isTrusted(out)) {
    +                    out.write(getBufIfOpen(), pos, avail);
    +                } else {
    +                    // Prevent poisoning and leaking of buf
    +                    byte[] buffer = Arrays.copyOfRange(getBufIfOpen(), pos, count);
    +                    out.write(buffer);
    +                }
                     pos = count;
                 }
                 try {
    @@ -658,4 +662,22 @@ private long implTransferTo(OutputStream out) throws IOException {
             }
         }
     
    +    /**
    +     * Returns true if this class satisfies the following conditions:
    +     * 
      + *
    • does not retain a reference to the {@code byte[]}
    • + *
    • does not leak a reference to the {@code byte[]} to non-trusted classes
    • + *
    • does not modify the contents of the {@code byte[]}
    • + *
    • {@code write()} method does not read the contents outside of the offset/length bounds
    • + *
    + * + * @return true if this class is trusted + */ + private static boolean isTrusted(OutputStream os) { + var clazz = os.getClass(); + return clazz == ByteArrayOutputStream.class + || clazz == FileOutputStream.class + || clazz == PipedOutputStream.class; + } + } diff --git a/src/java.base/share/classes/java/io/SequenceInputStream.java b/src/java.base/share/classes/java/io/SequenceInputStream.java index de3fafc884d..b89d9ca80b0 100644 --- a/src/java.base/share/classes/java/io/SequenceInputStream.java +++ b/src/java.base/share/classes/java/io/SequenceInputStream.java @@ -242,11 +242,14 @@ public long transferTo(OutputStream out) throws IOException { if (getClass() == SequenceInputStream.class) { long transferred = 0; while (in != null) { + long numTransferred = in.transferTo(out); + // increment the total transferred byte count + // only if we haven't already reached the Long.MAX_VALUE if (transferred < Long.MAX_VALUE) { try { - transferred = Math.addExact(transferred, in.transferTo(out)); + transferred = Math.addExact(transferred, numTransferred); } catch (ArithmeticException ignore) { - return Long.MAX_VALUE; + transferred = Long.MAX_VALUE; } } nextStream(); diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 25ba87d91af..3987cab019a 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -262,7 +262,8 @@ public String toString() { /** * Returns a string describing this {@code Class}, including - * information about modifiers and type parameters. + * information about modifiers, {@link #isSealed() sealed}/{@code + * non-sealed} status, and type parameters. * * The string is formatted as a list of type modifiers, if any, * followed by the kind of type (empty string for primitive types @@ -317,6 +318,11 @@ public String toGenericString() { sb.append(' '); } + // A class cannot be strictfp and sealed/non-sealed so + // it is sufficient to check for sealed-ness after all + // modifiers are printed. + addSealingInfo(modifiers, sb); + if (isAnnotation()) { sb.append('@'); } @@ -350,6 +356,49 @@ else if (isRecord()) } } + private void addSealingInfo(int modifiers, StringBuilder sb) { + // A class can be final XOR sealed XOR non-sealed. + if (Modifier.isFinal(modifiers)) { + return; // no-op + } else { + if (isSealed()) { + sb.append("sealed "); + return; + } else { + // Check for sealed ancestor, which implies this class + // is non-sealed. + if (hasSealedAncestor(this)) { + sb.append("non-sealed "); + } + } + } + } + + private boolean hasSealedAncestor(Class clazz) { + // From JLS 8.1.1.2: + // "It is a compile-time error if a class has a sealed direct + // superclass or a sealed direct superinterface, and is not + // declared final, sealed, or non-sealed either explicitly or + // implicitly. + // Thus, an effect of the sealed keyword is to force all + // direct subclasses to explicitly declare whether they are + // final, sealed, or non-sealed. This avoids accidentally + // exposing a sealed class hierarchy to unwanted subclassing." + + // Therefore, will just check direct superclass and + // superinterfaces. + var superclass = clazz.getSuperclass(); + if (superclass != null && superclass.isSealed()) { + return true; + } + for (var superinterface : clazz.getInterfaces()) { + if (superinterface.isSealed()) { + return true; + } + } + return false; + } + static String typeVarBounds(TypeVariable typeVar) { Type[] bounds = typeVar.getBounds(); if (bounds.length == 1 && bounds[0].equals(Object.class)) { diff --git a/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java b/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java index 02e0683a1b9..a9b40d028f5 100644 --- a/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java +++ b/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,10 @@ import java.util.Set; import java.util.stream.Collectors; import static java.lang.StackWalker.Option.*; +import jdk.internal.access.JavaIOPrintStreamAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.InternalLock; +import jdk.internal.vm.Continuation; /** * Helper class to print the virtual thread stack trace when pinned. @@ -42,7 +46,8 @@ * code in that Class. This is used to avoid printing the same stack trace many times. */ class PinnedThreadPrinter { - static final StackWalker STACK_WALKER; + private static final JavaIOPrintStreamAccess JIOPSA = SharedSecrets.getJavaIOPrintStreamAccess(); + private static final StackWalker STACK_WALKER; static { var options = Set.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE); PrivilegedAction pa = () -> @@ -86,45 +91,59 @@ private static int hash(List stack) { } /** - * Prints the continuation stack trace. + * Returns true if the frame is native, a class initializer, or holds monitors. + */ + private static boolean isInterestingFrame(LiveStackFrame f) { + return f.isNativeMethod() + || "".equals(f.getMethodName()) + || (f.getMonitors().length > 0); + } + + /** + * Prints the current thread's stack trace. * * @param printAll true to print all stack frames, false to only print the * frames that are native or holding a monitor */ - static void printStackTrace(PrintStream out, boolean printAll) { + static void printStackTrace(PrintStream out, Continuation.Pinned reason, boolean printAll) { List stack = STACK_WALKER.walk(s -> s.map(f -> (LiveStackFrame) f) .filter(f -> f.getDeclaringClass() != PinnedThreadPrinter.class) .collect(Collectors.toList()) ); + Object lockObj = JIOPSA.lock(out); + if (lockObj instanceof InternalLock lock && lock.tryLock()) { + try { + // find the closest frame that is causing the thread to be pinned + stack.stream() + .filter(f -> isInterestingFrame(f)) + .map(LiveStackFrame::getDeclaringClass) + .findFirst() + .ifPresentOrElse(klass -> { + // print the stack trace if not already seen + int hash = hash(stack); + if (HASHES.get(klass).add(hash)) { + printStackTrace(out, reason, stack, printAll); + } + }, () -> printStackTrace(out, reason, stack, true)); // not found - // find the closest frame that is causing the thread to be pinned - stack.stream() - .filter(f -> (f.isNativeMethod() || f.getMonitors().length > 0)) - .map(LiveStackFrame::getDeclaringClass) - .findFirst() - .ifPresentOrElse(klass -> { - int hash = hash(stack); - Hashes hashes = HASHES.get(klass); - synchronized (hashes) { - // print the stack trace if not already seen - if (hashes.add(hash)) { - printStackTrace(stack, out, printAll); - } - } - }, () -> printStackTrace(stack, out, true)); // not found + } finally { + lock.unlock(); + } + } } - private static void printStackTrace(List stack, - PrintStream out, + private static void printStackTrace(PrintStream out, + Continuation.Pinned reason, + List stack, boolean printAll) { - out.println(Thread.currentThread()); + out.format("%s reason:%s%n", Thread.currentThread(), reason); for (LiveStackFrame frame : stack) { var ste = frame.toStackTraceElement(); int monitorCount = frame.getMonitors().length; if (monitorCount > 0) { out.format(" %s <== monitors:%d%n", ste, monitorCount); - } else if (frame.isNativeMethod() || printAll) { + } else if (printAll || isInterestingFrame(frame)) { out.format(" %s%n", ste); } } diff --git a/src/java.base/share/classes/java/lang/StringBuffer.java b/src/java.base/share/classes/java/lang/StringBuffer.java index ec7ecb5d245..d77462f0c70 100644 --- a/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/src/java.base/share/classes/java/lang/StringBuffer.java @@ -715,6 +715,7 @@ public synchronized StringBuffer reverse() { */ @Override public synchronized StringBuffer repeat(int codePoint, int count) { + toStringCache = null; super.repeat(codePoint, count); return this; } @@ -726,6 +727,7 @@ public synchronized StringBuffer repeat(int codePoint, int count) { */ @Override public synchronized StringBuffer repeat(CharSequence cs, int count) { + toStringCache = null; super.repeat(cs, count); return this; } diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 42a1fa5ed21..b94b583962d 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -42,15 +42,10 @@ final class StringUTF16 { + // Return a new byte array for a UTF16-coded string for len chars + // Throw an exception if out of range public static byte[] newBytesFor(int len) { - if (len < 0) { - throw new NegativeArraySizeException(); - } - if (len > MAX_LENGTH) { - throw new OutOfMemoryError("UTF16 String size is " + len + - ", should be less than " + MAX_LENGTH); - } - return new byte[len << 1]; + return new byte[newBytesLength(len)]; } // Check the size of a UTF16-coded string @@ -59,7 +54,7 @@ public static int newBytesLength(int len) { if (len < 0) { throw new NegativeArraySizeException(); } - if (len > MAX_LENGTH) { + if (len >= MAX_LENGTH) { throw new OutOfMemoryError("UTF16 String size is " + len + ", should be less than " + MAX_LENGTH); } @@ -420,7 +415,7 @@ public static byte[] toBytes(int[] val, int index, int len) { int n = computeCodePointSize(val, index, end); byte[] buf = newBytesFor(n); - return extractCodepoints(val, index, len, buf, 0); + return extractCodepoints(val, index, end, buf, 0); } public static byte[] toBytes(char c) { diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 469bbd3894d..355b7cb8934 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ import java.security.ProtectionDomain; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -814,6 +815,10 @@ public static native void arraycopy(Object src, int srcPos, * Note that even if the security manager does not permit the * {@code getProperties} operation, it may choose to permit the * {@link #getProperty(String)} operation. + *

    + * Additional locale-related system properties defined by the + * {@link Locale##default_locale Default Locale} section in the {@code Locale} + * class description may also be obtained with this method. * * @apiNote * Changing a standard system property may have unpredictable results @@ -2375,7 +2380,7 @@ E[] getEnumConstantsShared(Class klass) { return klass.getEnumConstantsShared(); } public void blockedOn(Interruptible b) { - Thread.blockedOn(b); + Thread.currentThread().blockedOn(b); } public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) { Shutdown.add(slot, registerShutdownInProgress, hook); diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index ec578efd8ab..c3a6a3de5bc 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -345,15 +345,20 @@ void inheritScopedValueBindings(ThreadContainer container) { * operation, if any. The blocker's interrupt method should be invoked * after setting this thread's interrupt status. */ - volatile Interruptible nioBlocker; + private Interruptible nioBlocker; + + Interruptible nioBlocker() { + //assert Thread.holdsLock(interruptLock); + return nioBlocker; + } /* Set the blocker field; invoked via jdk.internal.access.SharedSecrets * from java.nio code */ - static void blockedOn(Interruptible b) { - Thread me = Thread.currentThread(); - synchronized (me.interruptLock) { - me.nioBlocker = b; + void blockedOn(Interruptible b) { + //assert Thread.currentThread() == this; + synchronized (interruptLock) { + nioBlocker = b; } } @@ -1647,7 +1652,7 @@ private void exit() { * interrupt the wait. * For more information, see * Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. + * is Thread.stop deprecated and the ability to stop a thread removed?. */ @Deprecated(since="1.2", forRemoval=true) public final void stop() { @@ -1699,15 +1704,19 @@ public void interrupt() { checkAccess(); // thread may be blocked in an I/O operation + Interruptible blocker; synchronized (interruptLock) { - Interruptible b = nioBlocker; - if (b != null) { + blocker = nioBlocker; + if (blocker != null) { interrupted = true; interrupt0(); // inform VM of interrupt - b.interrupt(this); - return; + blocker.interrupt(this); } } + if (blocker != null) { + blocker.postInterrupt(); + return; + } } interrupted = true; interrupt0(); // inform VM of interrupt @@ -1788,44 +1797,6 @@ boolean alive() { return eetop != 0; } - /** - * Throws {@code UnsupportedOperationException}. - * - * @throws UnsupportedOperationException always - * - * @deprecated This method was originally specified to suspend a thread. - * It was inherently deadlock-prone. If the target thread held a lock on - * a monitor protecting a critical system resource when it was suspended, - * no thread could access the resource until the target thread was resumed. - * If the thread intending to resume the target thread attempted to lock - * the monitor prior to calling {@code resume}, deadlock would result. - * Such deadlocks typically manifested themselves as "frozen" processes. - * For more information, see - * Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. - */ - @Deprecated(since="1.2", forRemoval=true) - public final void suspend() { - throw new UnsupportedOperationException(); - } - - /** - * Throws {@code UnsupportedOperationException}. - * - * @throws UnsupportedOperationException always - * - * @deprecated This method was originally specified to resume a thread - * suspended with {@link #suspend()}. Suspending a thread was - * inherently deadlock-prone. - * For more information, see - * Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. - */ - @Deprecated(since="1.2", forRemoval=true) - public final void resume() { - throw new UnsupportedOperationException(); - } - /** * Changes the priority of this thread. * diff --git a/src/java.base/share/classes/java/lang/ThreadGroup.java b/src/java.base/share/classes/java/lang/ThreadGroup.java index 48467f86e1e..51a96f37c5d 100644 --- a/src/java.base/share/classes/java/lang/ThreadGroup.java +++ b/src/java.base/share/classes/java/lang/ThreadGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -554,17 +554,6 @@ private int enumerate(ThreadGroup[] list, int i, boolean recurse) { return i; } - /** - * Throws {@code UnsupportedOperationException}. - * - * @deprecated This method was originally specified to stop all threads in - * the thread group. It was inherently unsafe. - */ - @Deprecated(since="1.2", forRemoval=true) - public final void stop() { - throw new UnsupportedOperationException(); - } - /** * Interrupts all {@linkplain Thread#isAlive() live} platform threads in * this thread group and its subgroups. @@ -587,28 +576,6 @@ public final void interrupt() { } } - /** - * Throws {@code UnsupportedOperationException}. - * - * @deprecated This method was originally specified to suspend all threads - * in the thread group. - */ - @Deprecated(since="1.2", forRemoval=true) - public final void suspend() { - throw new UnsupportedOperationException(); - } - - /** - * Throws {@code UnsupportedOperationException}. - * - * @deprecated This method was originally specified to resume all threads - * in the thread group. - */ - @Deprecated(since="1.2", forRemoval=true) - public final void resume() { - throw new UnsupportedOperationException(); - } - /** * Does nothing. * diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 2707b3ba9bd..72ae1070242 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,7 +191,15 @@ private static class VThreadContinuation extends Continuation { protected void onPinned(Continuation.Pinned reason) { if (TRACE_PINNING_MODE > 0) { boolean printAll = (TRACE_PINNING_MODE == 1); - PinnedThreadPrinter.printStackTrace(System.out, printAll); + VirtualThread vthread = (VirtualThread) Thread.currentThread(); + int oldState = vthread.state(); + try { + // avoid printing when in transition states + vthread.setState(RUNNING); + PinnedThreadPrinter.printStackTrace(System.out, reason, printAll); + } finally { + vthread.setState(oldState); + } } } private static Runnable wrap(VirtualThread vthread, Runnable task) { @@ -743,11 +751,16 @@ void unpark() { } } else if ((s == PINNED) || (s == TIMED_PINNED)) { // unpark carrier thread when pinned - synchronized (carrierThreadAccessLock()) { - Thread carrier = carrierThread; - if (carrier != null && ((s = state()) == PINNED || s == TIMED_PINNED)) { - U.unpark(carrier); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + Thread carrier = carrierThread; + if (carrier != null && ((s = state()) == PINNED || s == TIMED_PINNED)) { + U.unpark(carrier); + } } + } finally { + notifyJvmtiDisableSuspend(false); } } } @@ -839,21 +852,45 @@ boolean joinNanos(long nanos) throws InterruptedException { return true; } + @Override + void blockedOn(Interruptible b) { + notifyJvmtiDisableSuspend(true); + try { + super.blockedOn(b); + } finally { + notifyJvmtiDisableSuspend(false); + } + } + @Override @SuppressWarnings("removal") public void interrupt() { if (Thread.currentThread() != this) { checkAccess(); - synchronized (interruptLock) { - interrupted = true; - Interruptible b = nioBlocker; - if (b != null) { - b.interrupt(this); + + // if current thread is a virtual thread then prevent it from being + // suspended when entering or holding interruptLock + Interruptible blocker; + notifyJvmtiDisableSuspend(true); + try { + synchronized (interruptLock) { + interrupted = true; + blocker = nioBlocker(); + if (blocker != null) { + blocker.interrupt(this); + } + + // interrupt carrier thread if mounted + Thread carrier = carrierThread; + if (carrier != null) carrier.setInterrupt(); } + } finally { + notifyJvmtiDisableSuspend(false); + } - // interrupt carrier thread if mounted - Thread carrier = carrierThread; - if (carrier != null) carrier.setInterrupt(); + // notify blocker after releasing interruptLock + if (blocker != null) { + blocker.postInterrupt(); } } else { interrupted = true; @@ -872,9 +909,14 @@ boolean getAndClearInterrupt() { assert Thread.currentThread() == this; boolean oldValue = interrupted; if (oldValue) { - synchronized (interruptLock) { - interrupted = false; - carrierThread.clearInterrupt(); + notifyJvmtiDisableSuspend(true); + try { + synchronized (interruptLock) { + interrupted = false; + carrierThread.clearInterrupt(); + } + } finally { + notifyJvmtiDisableSuspend(false); } } return oldValue; @@ -899,11 +941,16 @@ Thread.State threadState() { return Thread.State.RUNNABLE; case RUNNING: // if mounted then return state of carrier thread - synchronized (carrierThreadAccessLock()) { - Thread carrierThread = this.carrierThread; - if (carrierThread != null) { - return carrierThread.threadState(); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + Thread carrierThread = this.carrierThread; + if (carrierThread != null) { + return carrierThread.threadState(); + } } + } finally { + notifyJvmtiDisableSuspend(false); } // runnable, mounted return Thread.State.RUNNABLE; @@ -955,12 +1002,12 @@ StackTraceElement[] asyncGetStackTrace() { * Returns null if the thread is mounted or in transition. */ private StackTraceElement[] tryGetStackTrace() { - int initialState = state(); + int initialState = state() & ~SUSPENDED; switch (initialState) { case NEW, STARTED, TERMINATED -> { return new StackTraceElement[0]; // unmounted, empty stack } - case RUNNING, PINNED -> { + case RUNNING, PINNED, TIMED_PINNED -> { return null; // mounted } case PARKED, TIMED_PARKED -> { @@ -972,7 +1019,7 @@ private StackTraceElement[] tryGetStackTrace() { case PARKING, TIMED_PARKING, YIELDING -> { return null; // in transition } - default -> throw new InternalError(); + default -> throw new InternalError("" + initialState); } // thread is unmounted, prevent it from continuing @@ -1019,14 +1066,19 @@ public String toString() { Thread carrier = carrierThread; if (carrier != null) { // include the carrier thread state and name when mounted - synchronized (carrierThreadAccessLock()) { - carrier = carrierThread; - if (carrier != null) { - String stateAsString = carrier.threadState().toString(); - sb.append(stateAsString.toLowerCase(Locale.ROOT)); - sb.append('@'); - sb.append(carrier.getName()); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + carrier = carrierThread; + if (carrier != null) { + String stateAsString = carrier.threadState().toString(); + sb.append(stateAsString.toLowerCase(Locale.ROOT)); + sb.append('@'); + sb.append(carrier.getName()); + } } + } finally { + notifyJvmtiDisableSuspend(false); } } // include virtual thread state when not mounted @@ -1125,6 +1177,9 @@ private void setCarrierThread(Thread carrier) { @JvmtiMountTransition private native void notifyJvmtiHideFrames(boolean hide); + @IntrinsicCandidate + private native void notifyJvmtiDisableSuspend(boolean enter); + private static native void registerNatives(); static { registerNatives(); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index 05c1e792d9e..721719d2851 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -202,7 +202,7 @@ default ModuleAttributeBuilder moduleFlags(AccessFlag... moduleFlags) { } /** - * Sets the module flags + * Sets the module version * @param version the module version * @return this builder */ diff --git a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html index fd5ced83fc0..6172a859ba6 100644 --- a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html +++ b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html @@ -1,6 +1,6 @@ - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentSettings.xml b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentSettings.xml index d9469aba6b1..50a58be99cd 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentSettings.xml +++ b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentSettings.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentWstcref.xml b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentWstcref.xml index a680c8f02fe..3e0a7c7db2e 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentWstcref.xml +++ b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponentWstcref.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/layer.xml b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/layer.xml index c864c8d9269..ae88bac2414 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/layer.xml +++ b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/resources/com/sun/hotspot/igv/bytecodes/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml b/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml index 9b77a418dd2..a75a439c011 100644 --- a/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml +++ b/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentSettings.xml b/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentSettings.xml index e226cd5ece9..5ffb8213fbc 100644 --- a/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentSettings.xml +++ b/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentSettings.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentWstcref.xml b/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentWstcref.xml index 07bbb1f52fb..66bc3093c7e 100644 --- a/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentWstcref.xml +++ b/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/ControlFlowTopComponentWstcref.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/layer.xml b/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/layer.xml index 176712f1595..5e79cc22ee7 100644 --- a/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/layer.xml +++ b/src/utils/IdealGraphVisualizer/ControlFlow/src/main/resources/com/sun/hotspot/igv/controlflow/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Coordinator/pom.xml b/src/utils/IdealGraphVisualizer/Coordinator/pom.xml index e93c6d20a40..718ef67044e 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/pom.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentSettings.xml b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentSettings.xml index 1acdbcbe986..7f2a5a45a0f 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentSettings.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentSettings.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentWstcref.xml b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentWstcref.xml index 329140ea6bd..e0d1d62766c 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentWstcref.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/OutlineTopComponentWstcref.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/StandardConfiguration.xml b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/StandardConfiguration.xml index ada940d0094..2412c5fed21 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/StandardConfiguration.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/StandardConfiguration.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml index c4759676284..60e73788c95 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Data/pom.xml b/src/utils/IdealGraphVisualizer/Data/pom.xml index 832be674e98..90010dd7001 100644 --- a/src/utils/IdealGraphVisualizer/Data/pom.xml +++ b/src/utils/IdealGraphVisualizer/Data/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd b/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd index be576142ed4..4e02fb64bb9 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd +++ b/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd @@ -1,6 +1,6 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Difference/pom.xml b/src/utils/IdealGraphVisualizer/Difference/pom.xml index d4605c60727..d51896a5d96 100644 --- a/src/utils/IdealGraphVisualizer/Difference/pom.xml +++ b/src/utils/IdealGraphVisualizer/Difference/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Filter/pom.xml b/src/utils/IdealGraphVisualizer/Filter/pom.xml index fa5089c8e65..e000c824f4f 100644 --- a/src/utils/IdealGraphVisualizer/Filter/pom.xml +++ b/src/utils/IdealGraphVisualizer/Filter/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/layer.xml b/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/layer.xml index 32fe79fc1a8..0cd6bc645b6 100644 --- a/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/layer.xml +++ b/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml b/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml index 1617e1a5fa7..4a4034c864f 100644 --- a/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml +++ b/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentSettings.xml b/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentSettings.xml index 6ae22f0fcd8..516361b0e88 100644 --- a/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentSettings.xml +++ b/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentSettings.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentWstcref.xml b/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentWstcref.xml index cc493bc5d6d..29efbd5705d 100644 --- a/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentWstcref.xml +++ b/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/FilterTopComponentWstcref.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/layer.xml b/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/layer.xml index aabc0e3829c..72802a59b8a 100644 --- a/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/layer.xml +++ b/src/utils/IdealGraphVisualizer/FilterWindow/src/main/resources/com/sun/hotspot/igv/filterwindow/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Graph/pom.xml b/src/utils/IdealGraphVisualizer/Graph/pom.xml index 3dba21fa7a0..d828c9140ab 100644 --- a/src/utils/IdealGraphVisualizer/Graph/pom.xml +++ b/src/utils/IdealGraphVisualizer/Graph/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml b/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml index 4a99ff829d5..64d1f8f58dc 100644 --- a/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml +++ b/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Layout/pom.xml b/src/utils/IdealGraphVisualizer/Layout/pom.xml index 6a046b5e6b8..42975afd54d 100644 --- a/src/utils/IdealGraphVisualizer/Layout/pom.xml +++ b/src/utils/IdealGraphVisualizer/Layout/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml b/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml index 93ffbcee64b..b755fec8fc6 100644 --- a/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml +++ b/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/README.md b/src/utils/IdealGraphVisualizer/README.md index f930ea604a4..83c9ee5889b 100644 --- a/src/utils/IdealGraphVisualizer/README.md +++ b/src/utils/IdealGraphVisualizer/README.md @@ -28,10 +28,11 @@ Ideal graphs are dumped at the following points: * `N=0`: no output (default) * `N=1`: after parsing, before matching, and final code (also for failed compilations, if available) -* `N=2`: additionally, after every major phase (including loop opts) +* `N=2`: additionally, after every major phase * `N=3`: additionally, after every minor phase -* `N=4`: additionally, after every effective IGVN step (slow) -* `N=5`: additionally, after parsing every bytecode (very slow) +* `N=4`: additionally, after every loop optimization +* `N=5`: additionally, after every effective IGVN step (slow) +* `N=6`: additionally, after parsing every bytecode (very slow) By default the JVM expects that it will connect to a visualizer on the local host on port 4444. This can be configured using the options diff --git a/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml b/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml index cf813426bde..8dd8dda05af 100644 --- a/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml +++ b/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml b/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml index 86980e79c50..59d4cce7a46 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml index 24533b75af0..808a281fee4 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Settings/pom.xml b/src/utils/IdealGraphVisualizer/Settings/pom.xml index 4003013bfa6..21f92b3001d 100644 --- a/src/utils/IdealGraphVisualizer/Settings/pom.xml +++ b/src/utils/IdealGraphVisualizer/Settings/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/Settings/src/main/resources/com/sun/hotspot/igv/settings/layer.xml b/src/utils/IdealGraphVisualizer/Settings/src/main/resources/com/sun/hotspot/igv/settings/layer.xml index 789b0ee8fd8..35738694057 100644 --- a/src/utils/IdealGraphVisualizer/Settings/src/main/resources/com/sun/hotspot/igv/settings/layer.xml +++ b/src/utils/IdealGraphVisualizer/Settings/src/main/resources/com/sun/hotspot/igv/settings/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Util/pom.xml b/src/utils/IdealGraphVisualizer/Util/pom.xml index bc27c79d175..664ad35ef77 100644 --- a/src/utils/IdealGraphVisualizer/Util/pom.xml +++ b/src/utils/IdealGraphVisualizer/Util/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/View/pom.xml b/src/utils/IdealGraphVisualizer/View/pom.xml index c66cb8c9a24..2ffb98774cf 100644 --- a/src/utils/IdealGraphVisualizer/View/pom.xml +++ b/src/utils/IdealGraphVisualizer/View/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 IdealGraphVisualizer-parent diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml index 4e0417884a2..d50f7c914cc 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml +++ b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml @@ -1,5 +1,5 @@ - + diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWsmode.xml b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWsmode.xml index 22540d0628b..d5ba5b18fc1 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWsmode.xml +++ b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWsmode.xml @@ -2,7 +2,7 @@ + "https://www.netbeans.org/dtds/mode-properties2_0.dtd"> diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWstcref.xml b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWstcref.xml index a706bb6e265..cfba9aebfce 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWstcref.xml +++ b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/propertiesWstcref.xml @@ -2,7 +2,7 @@ + "https://www.netbeans.org/dtds/tc-ref2_0.dtd"> diff --git a/src/utils/IdealGraphVisualizer/application/pom.xml b/src/utils/IdealGraphVisualizer/application/pom.xml index d202691a4ab..8266f2cf9e1 100644 --- a/src/utils/IdealGraphVisualizer/application/pom.xml +++ b/src/utils/IdealGraphVisualizer/application/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 com.sun.hotspot.igv diff --git a/src/utils/IdealGraphVisualizer/branding/pom.xml b/src/utils/IdealGraphVisualizer/branding/pom.xml index ed33298d3e4..522445d8978 100644 --- a/src/utils/IdealGraphVisualizer/branding/pom.xml +++ b/src/utils/IdealGraphVisualizer/branding/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 com.sun.hotspot.igv diff --git a/src/utils/IdealGraphVisualizer/pom.xml b/src/utils/IdealGraphVisualizer/pom.xml index 9363b05ae1f..772916540ff 100644 --- a/src/utils/IdealGraphVisualizer/pom.xml +++ b/src/utils/IdealGraphVisualizer/pom.xml @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 com.sun.hotspot.igv IdealGraphVisualizer-parent diff --git a/src/utils/LogCompilation/pom.xml b/src/utils/LogCompilation/pom.xml index 1d8e0ffa1bd..e033a3fbc07 100644 --- a/src/utils/LogCompilation/pom.xml +++ b/src/utils/LogCompilation/pom.xml @@ -29,15 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + 4.0.0 com.sun.hotspot.tools.compiler LogCompilation jar 1.0-SNAPSHOT LogCompilation - http://maven.apache.org + https://maven.apache.org junit diff --git a/test/hotspot/gtest/gc/shared/test_bufferNodeAllocator.cpp b/test/hotspot/gtest/gc/shared/test_bufferNodeAllocator.cpp index e07e073974f..752aef02d5a 100644 --- a/test/hotspot/gtest/gc/shared/test_bufferNodeAllocator.cpp +++ b/test/hotspot/gtest/gc/shared/test_bufferNodeAllocator.cpp @@ -239,7 +239,7 @@ static void run_test(BufferNode::Allocator* allocator, CompletedList* cbl) { } TEST_VM(BufferNodeAllocatorTest, stress_free_list_allocator) { - const size_t buffer_capacity = DEFAULT_CACHE_LINE_SIZE / sizeof(void*); + const size_t buffer_capacity = DEFAULT_PADDING_SIZE / sizeof(void*); BufferNode::Allocator allocator("Test Allocator", buffer_capacity); CompletedList completed; run_test(&allocator, &completed); diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 55d1785aed6..f591eefe3ef 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -72,8 +72,6 @@ compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x6 compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all -compiler/codecache/CheckLargePages.java 8319795 linux-x64 - compiler/floatingpoint/TestSubnormalFloat.java 8317810 generic-i586 compiler/floatingpoint/TestSubnormalDouble.java 8317810 generic-i586 @@ -85,10 +83,12 @@ gc/epsilon/TestMemoryMXBeans.java 8206434 generic-all gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 generic-all gc/g1/logging/TestG1LoggingFailure.java 8169634 generic-all gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all +gc/TestAllocHumongousFragment.java#adaptive 8298781 generic-all +gc/TestAllocHumongousFragment.java#aggressive 8298781 generic-all +gc/TestAllocHumongousFragment.java#iu-aggressive 8298781 generic-all +gc/TestAllocHumongousFragment.java#g1 8298781 generic-all +gc/TestAllocHumongousFragment.java#static 8298781 generic-all gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all -gc/stress/gclocker/TestGCLockerWithParallel.java 8180622 generic-all -gc/stress/gclocker/TestGCLockerWithSerial.java 8180622 generic-all -gc/stress/gclocker/TestGCLockerWithShenandoah.java 8180622 generic-all gc/stress/TestStressG1Humongous.java 8286554 windows-x64 ############################################################################# @@ -105,6 +105,7 @@ runtime/os/TestTracePageSizes.java#G1 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 +runtime/CompressedOops/CompressedClassPointers.java 8322943 aix-ppc64 runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le @@ -115,7 +116,6 @@ applications/jcstress/copy.java 8229852 linux-all containers/docker/TestJcmd.java 8278102 linux-all containers/docker/TestMemoryAwareness.java 8303470 linux-all -runtime/CompressedOops/CompressedClassPointers.java 8317610 linux-x64,windows-x64 # Valhalla runtime/AccModule/ConstModule.java 8294051 generic-all @@ -141,7 +141,7 @@ serviceability/sa/ClhsdbPstack.java#core 8267433 macosx-x64 serviceability/sa/TestJmapCore.java 8267433 macosx-x64 serviceability/sa/TestJmapCoreMetaspace.java 8267433 macosx-x64 -serviceability/attach/ConcAttachTest.java 8290043,8318866 linux-all,macosx-all +serviceability/attach/ConcAttachTest.java 8290043 linux-all serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index a482680bfaa..bbc18474ca4 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -372,7 +372,6 @@ tier2_gc_shenandoah = \ tier3_gc_shenandoah = \ gc/stress/gcold/TestGCOldWithShenandoah.java \ gc/stress/gcbasher/TestGCBasherWithShenandoah.java \ - gc/stress/gclocker/TestGCLockerWithShenandoah.java \ gc/stress/systemgc/TestSystemGCWithShenandoah.java \ gc/shenandoah/TestStringDedupStress.java \ -:tier2_gc_shenandoah diff --git a/test/hotspot/jtreg/compiler/arguments/TestC1Globals.java b/test/hotspot/jtreg/compiler/arguments/TestC1Globals.java index b8ed2c36918..3944b78bc27 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestC1Globals.java +++ b/test/hotspot/jtreg/compiler/arguments/TestC1Globals.java @@ -23,11 +23,11 @@ /** * @test - * @bug 8318817 + * @bug 8316653 * @requires vm.debug - * @summary Test flag with large value + * @summary Test flag with max value. * - * @run main/othervm -XX:NMethodSizeLimit=351658240 + * @run main/othervm -XX:NMethodSizeLimit=1M * compiler.arguments.TestC1Globals */ @@ -35,48 +35,37 @@ * @test * @bug 8318817 * @requires vm.debug - * @summary Test flag with large value - * - * @run main/othervm -XX:NMethodSizeLimit=224001703 - * compiler.arguments.TestC1Globals - */ - -/** - * @test - * @bug 8316653 - * @requires vm.debug - * @summary Test flag with max value + * @requires os.family == "linux" + * @summary Test flag with max value combined with transparent huge pages on + * Linux. * - * @run main/othervm -XX:NMethodSizeLimit=2147483647 + * @run main/othervm -XX:NMethodSizeLimit=1M + * -XX:+UseTransparentHugePages * compiler.arguments.TestC1Globals */ /** * @test - * @bug 8318817 + * @bug 8320682 * @requires vm.debug - * @requires os.family == "linux" - * @summary Test flag with large value combined with transparent huge pages on - * Linux. + * @summary Test flag with max value and specific compilation. * - * @run main/othervm -XX:NMethodSizeLimit=351658240 - * -XX:+UseTransparentHugePages + * @run main/othervm -XX:NMethodSizeLimit=1M + * -XX:CompileOnly=java.util.HashMap::putMapEntries + * -Xcomp * compiler.arguments.TestC1Globals * */ /** * @test - * @bug 8318817 + * @bug 8322781 * @requires vm.debug - * @requires os.family == "linux" - * @summary Test flag with large value combined with transparent huge pages on - * Linux. + * @summary Test flag with c1 value numbering * - * @run main/othervm -XX:NMethodSizeLimit=224001703 - * -XX:+UseTransparentHugePages + * @run main/othervm -XX:+PrintValueNumbering -XX:+Verbose -XX:-UseLocalValueNumbering + * -Xcomp -XX:TieredStopAtLevel=1 * compiler.arguments.TestC1Globals - * */ package compiler.arguments; diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileThresholdScaling.java b/test/hotspot/jtreg/compiler/arguments/TestCompileThresholdScaling.java index c417cc66248..47025572428 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileThresholdScaling.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileThresholdScaling.java @@ -48,7 +48,7 @@ public static void main(String args[]) throws Throwable { } static void checkCompileThresholdScaling(double value, boolean fail) throws Throwable { - OutputAnalyzer out = ProcessTools.executeTestJvm("-XX:CompileThresholdScaling=" + value, "--version"); + OutputAnalyzer out = ProcessTools.executeTestJava("-XX:CompileThresholdScaling=" + value, "--version"); out.shouldHaveExitValue(0); String output = out.getOutput(); diff --git a/test/hotspot/jtreg/compiler/arguments/TestTraceICs.java b/test/hotspot/jtreg/compiler/arguments/TestTraceICs.java index 2be8f73cccf..02a479615f4 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestTraceICs.java +++ b/test/hotspot/jtreg/compiler/arguments/TestTraceICs.java @@ -24,8 +24,8 @@ /* * @test * @bug 8217447 - * @summary Test running TraceICs enabled. - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceICs + * @summary Test running with log:inlinecache=trace enabled. + * @run main/othervm -Xlog:inlinecache=trace * compiler.arguments.TestTraceICs */ diff --git a/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java b/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java new file mode 100644 index 00000000000..d5cdb6bee52 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8310844 + * @summary Verify that monitors with large offset in the OSR buffer are handled properly. + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestLargeMonitorOffset::* TestLargeMonitorOffset + */ + +public class TestLargeMonitorOffset { + + public static void test() { + long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, + l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, + l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, + l31, l32, l33, l34, l35, l36, l37, l38, l39, l40, + l41, l42, l43, l44, l45, l46, l47, l48, l49, l50, + l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, + l71, l72, l73, l74, l75, l76, l77, l78, l79, l80, + l81, l82, l83, l84, l85, l86, l87, l88, l89, l90, + l91, l92, l93, l94, l95, l96, l97, l98, l99, l100, + l101, l102, l103, l104, l105, l106, l107, l108, l109, l110, + l111, l112, l113, l114, l115, l116, l117, l118, l119, l120, + l121, l122, l123, l124, l125, l126, l127, l128, l129, l130, + l131, l132, l133, l134, l135, l136, l137, l138, l139, l140, + l141, l142, l143, l144, l145, l146, l147, l148, l149, l150, + l151, l152, l153, l154, l155, l156, l157, l158, l159, l160, + l161, l162, l163, l164, l165, l166, l167, l168, l169, l170, + l171, l172, l173, l174, l175, l176, l177, l178, l179, l180, + l181, l182, l183, l184, l185, l186, l187, l188, l189, l190, + l191, l192, l193, l194, l195, l196, l197, l198, l199, l200, + l201, l202, l203, l204, l205, l206, l207, l208, l209, l210, + l211, l212, l213, l214, l215, l216, l217, l218, l219, l220, + l221, l222, l223, l224, l225, l226, l227, l228, l229, l230, + l231, l232, l233, l234, l235, l236, l237, l238, l239, l240, + l241, l242, l243, l244, l245, l246, l247, l248, l249, l250, + l251, l252, l253, l254, l255, l256, l257, l258, l259, l260, + l261, l262, l263, l264, l265, l266, l267, l268, l269, l270, + l271, l272, l273, l274, l275, l276, l277, l278, l279, l280, + l281, l282, l283, l284, l285, l286, l287, l288, l289, l290, + l291, l292, l293, l294, l295, l296, l297, l298, l299, l300, + l301, l302, l303, l304, l305, l306, l307, l308, l309, l310, + l311, l312, l313, l314, l315, l316, l317, l318, l319, l320, + l321, l322, l323, l324, l325, l326, l327, l328, l329, l330, + l331, l332, l333, l334, l335, l336, l337, l338, l339, l340, + l341, l342, l343, l344, l345, l346, l347, l348, l349, l350, + l351, l352, l353, l354, l355, l356, l357, l358, l359, l360, + l361, l362, l363, l364, l365, l366, l367, l368, l369, l370, + l371, l372, l373, l374, l375, l376, l377, l378, l379, l380, + l381, l382, l383, l384, l385, l386, l387, l388, l389, l390, + l391, l392, l393, l394, l395, l396, l397, l398, l399, l400, + l401, l402, l403, l404, l405, l406, l407, l408, l409, l410, + l411, l412, l413, l414, l415, l416, l417, l418, l419, l420, + l421, l422, l423, l424, l425, l426, l427, l428, l429, l430, + l431, l432, l433, l434, l435, l436, l437, l438, l439, l440, + l441, l442, l443, l444, l445, l446, l447, l448, l449, l450, + l451, l452, l453, l454, l455, l456, l457, l458, l459, l460, + l461, l462, l463, l464, l465, l466, l467, l468, l469, l470, + l471, l472, l473, l474, l475, l476, l477, l478, l479, l480, + l481, l482, l483, l484, l485, l486, l487, l488, l489, l490, + l491, l492, l493, l494, l495, l496, l497, l498, l499, l500, + l501, l502, l503, l504, l505, l506, l507, l508, l509, l510, + l511, l512, l513, l514, l515, l516, l517, l518, l519, l520, + l521, l522, l523, l524, l525, l526, l527, l528, l529, l530, + l531, l532, l533, l534, l535, l536, l537, l538, l539, l540, + l541, l542, l543, l544, l545, l546, l547, l548, l549, l550, + l551, l552, l553, l554, l555, l556, l557, l558, l559, l560, + l561, l562, l563, l564, l565, l566, l567, l568, l569, l570, + l571, l572, l573, l574, l575, l576, l577, l578, l579, l580, + l581, l582, l583, l584, l585, l586, l587, l588, l589, l590, + l591, l592, l593, l594, l595, l596, l597, l598, l599, l600, + l601, l602, l603, l604, l605, l606, l607, l608, l609, l610, + l611, l612, l613, l614, l615, l616, l617, l618, l619, l620, + l621, l622, l623, l624, l625, l626, l627, l628, l629, l630, + l631, l632, l633, l634, l635, l636, l637, l638, l639, l640, + l641, l642, l643, l644, l645, l646, l647, l648, l649, l650, + l651, l652, l653, l654, l655, l656, l657, l658, l659, l660, + l661, l662, l663, l664, l665, l666, l667, l668, l669, l670, + l671, l672, l673, l674, l675, l676, l677, l678, l679, l680, + l681, l682, l683, l684, l685, l686, l687, l688, l689, l690, + l691, l692, l693, l694, l695, l696, l697, l698, l699, l700, + l701, l702, l703, l704, l705, l706, l707, l708, l709, l710, + l711, l712, l713, l714, l715, l716, l717, l718, l719, l720, + l721, l722, l723, l724, l725, l726, l727, l728, l729, l730, + l731, l732, l733, l734, l735, l736, l737, l738, l739, l740, + l741, l742, l743, l744, l745, l746, l747, l748, l749, l750, + l751, l752, l753, l754, l755, l756, l757, l758, l759, l760, + l761, l762, l763, l764, l765, l766, l767, l768, l769, l770, + l771, l772, l773, l774, l775, l776, l777, l778, l779, l780, + l781, l782, l783, l784, l785, l786, l787, l788, l789, l790, + l791, l792, l793, l794, l795, l796, l797, l798, l799, l800, + l801, l802, l803, l804, l805, l806, l807, l808, l809, l810, + l811, l812, l813, l814, l815, l816, l817, l818, l819, l820, + l821, l822, l823, l824, l825, l826, l827, l828, l829, l830, + l831, l832, l833, l834, l835, l836, l837, l838, l839, l840, + l841, l842, l843, l844, l845, l846, l847, l848, l849, l850, + l851, l852, l853, l854, l855, l856, l857, l858, l859, l860, + l861, l862, l863, l864, l865, l866, l867, l868, l869, l870, + l871, l872, l873, l874, l875, l876, l877, l878, l879, l880, + l881, l882, l883, l884, l885, l886, l887, l888, l889, l890, + l891, l892, l893, l894, l895, l896, l897, l898, l899, l900, + l901, l902, l903, l904, l905, l906, l907, l908, l909, l910, + l911, l912, l913, l914, l915, l916, l917, l918, l919, l920, + l921, l922, l923, l924, l925, l926, l927, l928, l929, l930, + l931, l932, l933, l934, l935, l936, l937, l938, l939, l940, + l941, l942, l943, l944, l945, l946, l947, l948, l949, l950, + l951, l952, l953, l954, l955, l956, l957, l958, l959, l960, + l961, l962, l963, l964, l965, l966, l967, l968, l969, l970, + l971, l972, l973, l974, l975, l976, l977, l978, l979, l980, + l981, l982, l983, l984, l985, l986, l987, l988, l989, l990, + l991, l992, l993, l994, l995, l996, l997, l998, l999, l1000; + + synchronized (TestLargeMonitorOffset.class) { + // Trigger OSR compilation with monitor in the OSR buffer + for (int i = 0; i < 1_000_000; ++i) { + + } + } + } + + public static void main(String[] args) { + test(); + } +} diff --git a/test/hotspot/jtreg/compiler/c1/TestPrintC1Statistics.java b/test/hotspot/jtreg/compiler/c1/TestPrintC1Statistics.java index 854ccd907c9..3d62aa4d271 100644 --- a/test/hotspot/jtreg/compiler/c1/TestPrintC1Statistics.java +++ b/test/hotspot/jtreg/compiler/c1/TestPrintC1Statistics.java @@ -44,7 +44,7 @@ public static void main(String[] args) throws Exception { options.add("-XX:+PrintC1Statistics"); options.add("--version"); - OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + OutputAnalyzer oa = ProcessTools.executeTestJava(options); oa.shouldHaveExitValue(0).shouldContain("C1 Runtime statistics"); } diff --git a/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java b/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java new file mode 100644 index 00000000000..3bad2bde7b1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8321974 + * @summary Test that the TypeAryPtr::_klass field is properly initialized on use. + * @comment This test only reproduces the issue with release builds of the JVM because + * verification code in debug builds leads to eager initialization of the field. + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestUninitializedKlassField::test* + * -XX:-TieredCompilation TestUninitializedKlassField + */ + +public class TestUninitializedKlassField { + static void test(long array2[]) { + long array1[] = new long[1]; + // Loop is needed to create a backedge phi that is processed only during IGVN. + for (int i = 0; i < 1; i++) { + // CmpPNode::sub will check if classes of array1 and array2 are unrelated + // and the subtype checks will crash if the _klass field is not initialized. + if (array2 != array1) { + array1 = new long[2]; + } + } + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; ++i) { + test(null); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java index d461d56d8a3..3fe213122bd 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, BELLSOFT. All rights reserved. + * Copyright (c) 2024, BELLSOFT. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,10 +89,9 @@ static void runVM(boolean bigCodeHeap) throws Exception { "-Xbatch", "-XX:+TieredCompilation", "-XX:+SegmentedCodeCache", - "-XX:CompileOnly=" + className + "::main", "-XX:ReservedCodeCacheSize=" + (bigCodeHeap ? "256M" : "200M"), "-XX:+UnlockDiagnosticVMOptions", - "-XX:+PrintAssembly", + "-XX:CompileCommand=option," + className + "::main,bool,PrintAssembly,true", className}; ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs); diff --git a/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java b/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java index 8fc1fa0580d..9975fd7511c 100644 --- a/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java +++ b/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java @@ -44,7 +44,7 @@ public void run() throws Throwable { } private List executeApplication() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( "-Xbatch", "-XX:-TieredCompilation", "-XX:+PrintCompilation", diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java index ad2b52392b6..f20c28e321d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,22 +38,24 @@ public static void main(String[] args) { TestFramework.run(); } - @Run(test = { "test1" }) + @Run(test = { "test1", "test2" }) public void runMethod() { int a = RunInfo.getRandom().nextInt(); + int b = RunInfo.getRandom().nextInt(); int min = Integer.MIN_VALUE; int max = Integer.MAX_VALUE; - assertResult(0); - assertResult(a); - assertResult(min); - assertResult(max); + assertResult(0, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); } @DontCompile - public void assertResult(int a) { + public void assertResult(int a, int b) { Asserts.assertEQ((0 - a) & 1, test1(a)); + Asserts.assertEQ((~a) & (~b), test2(a, b)); } @Test @@ -63,4 +65,13 @@ public void assertResult(int a) { public int test1(int x) { return (0 - x) & 1; } + + @Test + @IR(failOn = { IRNode.AND }) + @IR(counts = { IRNode.OR, "1", + IRNode.XOR, "1" }) + // Checks (~a) & (~b) => ~(a | b) + public int test2(int a, int b) { + return (~a) & (~b); + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java new file mode 100644 index 00000000000..9aa1b62be97 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8322589 + * @summary Test that Ideal transformations of AndLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.AndLNodeIdealizationTests + */ +public class AndLNodeIdealizationTests { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { "test1" }) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + long b = RunInfo.getRandom().nextLong(); + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); + } + + @DontCompile + public void assertResult(long a, long b) { + Asserts.assertEQ((~a) & (~b), test1(a, b)); + } + + @Test + @IR(failOn = { IRNode.AND }) + @IR(counts = { IRNode.OR, "1", + IRNode.XOR, "1" }) + // Checks (~a) & (~b) => ~(a | b) + public long test1(long a, long b) { + return (~a) & (~b); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java index 3b7bf231730..b68ddfe2799 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java @@ -50,13 +50,10 @@ public class TestVectorizationMismatchedAccess { private final static WhiteBox wb = WhiteBox.getWhiteBox(); public static void main(String[] args) { - Object alignVector = wb.getVMFlag("AlignVector"); - if (alignVector != null && !((Boolean)alignVector)) { - if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) { - throw new RuntimeException("fix test that was written for a little endian platform"); - } - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); + if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) { + throw new RuntimeException("fix test that was written for a little endian platform"); } + TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); } static int size = 1024; @@ -189,7 +186,9 @@ public static void testByteLong3_runner() { } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIf = {"AlignVector", "false"}) + // AlignVector cannot guarantee that invar is aligned. public static void testByteLong4(byte[] dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, src[i]); @@ -323,7 +322,9 @@ public static void testOffHeapLong3_runner() { } @Test - @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" }, + applyIf = {"AlignVector", "false"}) + // AlignVector cannot guarantee that invar is aligned. public static void testOffHeapLong4(long dest, long[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(null, dest + 8 * i + baseOffset, src[i]); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestLoadNIdeal.java b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestLoadNIdeal.java new file mode 100644 index 00000000000..758ad60bec7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestLoadNIdeal.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests.igvn; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8310524 + * @requires vm.bits == 64 + * @summary Test that IGVN optimizes away one of two identical LoadNs. + * @library /test/lib / + * @run driver compiler.c2.irTests.igvn.TestLoadNIdeal + */ + +public class TestLoadNIdeal { + + public static void main(String[] args) { + // Ensure that we run with compressed oops + TestFramework.runWithFlags("-XX:+UseCompressedOops"); + } + + static class A { int x; } + + @DontInline + void dummy(A p[]) { } + + @Test + @IR(applyIf = { "UseCompressedOops", "true" }, counts = { IRNode.LOAD_N, "1" }) + int test() { + A p[] = new A[1]; + p[0] = new A(); + + // The dummy method is not inlined => Escape analysis + // cannot ensure that p[0] is unmodified after the call. + dummy(p); + + // We should only need to load p[0] once here. Storing A within an + // array adds range checks for the first load and ensures the second + // load is not optimized already at bytecode parsing. + return p[0].x + p[0].x; + } +} diff --git a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java index 6ad45edd26b..dcb8dff8f7d 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java +++ b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java @@ -105,9 +105,9 @@ static void test(int i) { static { try { - CLIENT_VM_AVAILABLE = ProcessTools.executeTestJvm(CLIENT_VM_OPTION, VERSION_OPTION) + CLIENT_VM_AVAILABLE = ProcessTools.executeTestJava(CLIENT_VM_OPTION, VERSION_OPTION) .getOutput().contains("Client"); - SERVER_VM_AVAILABLE = ProcessTools.executeTestJvm(SERVER_VM_OPTION, VERSION_OPTION) + SERVER_VM_AVAILABLE = ProcessTools.executeTestJava(SERVER_VM_OPTION, VERSION_OPTION) .getOutput().contains("Server"); } catch(Throwable t) { throw new Error("Initialization failed: " + t, t); diff --git a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java index 5b6274681f7..ee37b7a5164 100644 --- a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java +++ b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java @@ -44,35 +44,83 @@ import java.util.List; public class CheckLargePages { - private final static WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private final static long LP_1G = 1024 * 1024 * 1024; + private final static boolean LARGE_PAGES_ENABLED; + private final static long LARGE_PAGE_SIZE; + static { + WhiteBox whiteBox = WhiteBox.getWhiteBox(); + LARGE_PAGES_ENABLED = whiteBox.getBooleanVMFlag("UseLargePages"); + LARGE_PAGE_SIZE = (whiteBox.getBooleanVMFlag("UseLargePages")) ? whiteBox.getVMLargePageSize() : 0; + } + + private static boolean isLargePageSizeEqual(long size) { + return LARGE_PAGE_SIZE == size; + } + + private static void testSegmented2GbCodeCacheWith1GbPage() throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UseLargePages", + "-XX:+SegmentedCodeCache", + "-XX:InitialCodeCacheSize=2g", + "-XX:ReservedCodeCacheSize=2g", + "-XX:LargePageSizeInBytes=1g", + "-Xlog:pagesize=info", + "-version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldMatch("Code cache size too small for \\S* pages\\. Reverting to smaller page size \\((\\S*)\\)\\."); + out.shouldHaveExitValue(0); + // Parse page sizes to find next biggest page + String sizes = out.firstMatch("Usable page sizes:([^.]+)", 1); + List sizeList = Arrays.stream(sizes.trim().split("\\s*,\\s*")).map(CheckLargePages::parseMemoryString) + .sorted().toList(); + final int smallerPageSizeIndex = sizeList.indexOf(LARGE_PAGE_SIZE) - 1; + Asserts.assertGreaterThanOrEqual(smallerPageSizeIndex, 0); + final long smallerPageSize = sizeList.get(smallerPageSizeIndex); + // Retrieve reverted page size from code cache warning + String revertedSizeString = out.firstMatch( + "Code cache size too small for (\\S*) pages. Reverting to smaller page size \\((\\S*)\\)\\.", 2); + Asserts.assertEquals(parseMemoryString(revertedSizeString), smallerPageSize); + } + + private static void testDefaultCodeCacheWith1GbLargePages() throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UseLargePages", + "-XX:LargePageSizeInBytes=1g", + "-XX:+PrintCodeCache", + "-version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + out.shouldContain("CodeHeap 'non-nmethods'"); + out.shouldContain("CodeHeap 'profiled nmethods'"); + out.shouldContain("CodeHeap 'non-profiled nmethods'"); + } + + private static void testNonSegmented1GbCodeCacheWith1GbLargePages() throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+UseLargePages", + "-XX:LargePageSizeInBytes=1g", + "-XX:ReservedCodeCacheSize=1g", + "-XX:InitialCodeCacheSize=1g", + "-XX:+PrintCodeCache", + "-Xlog:pagesize=info", + "-version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + out.shouldNotContain("CodeHeap 'non-nmethods'"); + out.shouldNotContain("CodeHeap 'profiled nmethods'"); + out.shouldNotContain("CodeHeap 'non-profiled nmethods'"); + out.shouldContain("UseLargePages=1, UseTransparentHugePages=0"); + out.shouldMatch("CodeCache: min=1[gG] max=1[gG] base=[^ ]+ size=1[gG] page_size=1[gG]"); + } public static void main(String[] args) throws Exception { - final boolean largePages = WHITE_BOX.getBooleanVMFlag("UseLargePages"); - final long largePageSize = WHITE_BOX.getVMLargePageSize(); - if (largePages && (largePageSize == 1024 * 1024 * 1024)) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseLargePages", - "-XX:+SegmentedCodeCache", - "-XX:InitialCodeCacheSize=2g", - "-XX:ReservedCodeCacheSize=2g", - "-XX:LargePageSizeInBytes=1g", - "-Xlog:pagesize=info", - "-version"); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); - out.shouldMatch("Code cache size too small for \\S* pages\\. Reverting to smaller page size \\((\\S*)\\)\\."); - out.shouldHaveExitValue(0); - // Parse page sizes to find next biggest page - String sizes = out.firstMatch("Usable page sizes:([^.]+)", 1); - List sizeList = Arrays.stream(sizes.trim().split("\\s*,\\s*")).map(CheckLargePages::parseMemoryString).sorted().toList(); - final int smallerPageSizeIndex = sizeList.indexOf(largePageSize) - 1; - Asserts.assertGreaterThanOrEqual(smallerPageSizeIndex, 0); - final long smallerPageSize = sizeList.get(smallerPageSizeIndex); - // Retrieve reverted page size from code cache warning - String revertedSizeString = out.firstMatch("Code cache size too small for (\\S*) pages. Reverting to smaller page size \\((\\S*)\\)\\.", 2); - Asserts.assertEquals(parseMemoryString(revertedSizeString), smallerPageSize); + if (isLargePageSizeEqual(LP_1G)) { + testSegmented2GbCodeCacheWith1GbPage(); + testDefaultCodeCacheWith1GbLargePages(); + testNonSegmented1GbCodeCacheWith1GbLargePages(); } else { - System.out.println("1GB large pages not supported: UseLargePages=" + largePages + - (largePages ? ", largePageSize=" + largePageSize : "") + ". Skipping"); + System.out.println("1GB large pages not supported: UseLargePages=" + LARGE_PAGES_ENABLED + + (LARGE_PAGES_ENABLED ? ", largePageSize=" + LARGE_PAGE_SIZE : "") + ". Skipping"); } } diff --git a/test/hotspot/jtreg/compiler/compilercontrol/commands/MemLimitTest.java b/test/hotspot/jtreg/compiler/compilercontrol/commands/MemLimitTest.java index 5cf86794524..a6e16a317b0 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/commands/MemLimitTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/commands/MemLimitTest.java @@ -39,7 +39,7 @@ public class MemLimitTest { static void do_test(String option, boolean expectSuccess, int expectedValue) throws Exception { - OutputAnalyzer output = ProcessTools.executeTestJvm("-Xmx64m", "-XX:CompileCommand=" + option, "-version"); + OutputAnalyzer output = ProcessTools.executeTestJava("-Xmx64m", "-XX:CompileCommand=" + option, "-version"); if (expectSuccess) { output.shouldHaveExitValue(0); output.shouldNotContain("error occurred"); diff --git a/test/hotspot/jtreg/compiler/compilercontrol/commands/MemStatTest.java b/test/hotspot/jtreg/compiler/compilercontrol/commands/MemStatTest.java index 2b6208652d3..e54ce7592e1 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/commands/MemStatTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/commands/MemStatTest.java @@ -38,22 +38,22 @@ public class MemStatTest { public static void main(String[] args) throws Exception { // default => collect - ProcessTools.executeTestJvm("-XX:CompileCommand=MemStat,*.*", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=MemStat,*.*", "-version") .shouldHaveExitValue(0) .shouldNotContain("CompileCommand: An error occurred during parsing") .shouldContain("CompileCommand: MemStat *.* uintx MemStat = 1"); // should be registered // collect explicit - ProcessTools.executeTestJvm("-XX:CompileCommand=MemStat,*.*,collect", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=MemStat,*.*,collect", "-version") .shouldHaveExitValue(0) .shouldNotContain("CompileCommand: An error occurred during parsing") .shouldContain("CompileCommand: MemStat *.* uintx MemStat = 1"); // should be registered // print explicit - ProcessTools.executeTestJvm("-XX:CompileCommand=MemStat,*.*,print", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=MemStat,*.*,print", "-version") .shouldHaveExitValue(0) .shouldNotContain("CompileCommand: An error occurred during parsing") .shouldContain("CompileCommand: MemStat *.* uintx MemStat = 2"); // invalid suboption - ProcessTools.executeTestJvm("-XX:CompileCommand=MemStat,*.*,invalid", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=MemStat,*.*,invalid", "-version") .shouldNotHaveExitValue(0) .shouldContain("CompileCommand: An error occurred during parsing") .shouldContain("Error: Value cannot be read for option 'MemStat'") diff --git a/test/hotspot/jtreg/compiler/compilercontrol/commands/OptionTest.java b/test/hotspot/jtreg/compiler/compilercontrol/commands/OptionTest.java index 171caf685e2..7e9878f32b2 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/commands/OptionTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/commands/OptionTest.java @@ -37,13 +37,13 @@ public class OptionTest { public static void main(String[] args) throws Exception { - ProcessTools.executeTestJvm("-XX:CompileCommand=option,package/class,ccstrlist,ControlIntrinsic,+_getClass", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=option,package/class,ccstrlist,ControlIntrinsic,+_getClass", "-version") .shouldHaveExitValue(1) .shouldContain("CompileCommand: An error occurred during parsing") .shouldContain("Error: Did not specify any method name") .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); - ProcessTools.executeTestJvm("-XX:CompileCommand=option,*,ccstrlist,ControlIntrinsic,+_getClass", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=option,*,ccstrlist,ControlIntrinsic,+_getClass", "-version") .shouldHaveExitValue(1) .shouldContain("CompileCommand: An error occurred during parsing") .shouldContain("Error: Did not specify any method name") @@ -51,36 +51,36 @@ public static void main(String[] args) throws Exception { // corner case: // ccstrlist could be a valid method name, so it is accepted in the well-formed case. - ProcessTools.executeTestJvm("-XX:CompileCommand=option,*.ccstrlist,ccstrlist,ControlIntrinsic,+_getClass", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=option,*.ccstrlist,ccstrlist,ControlIntrinsic,+_getClass", "-version") .shouldContain("CompileCommand: ControlIntrinsic *.ccstrlist const char* ControlIntrinsic") .shouldHaveExitValue(0) .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); - ProcessTools.executeTestJvm("-XX:CompileCommand=option,*.*,ccstrlist,ControlIntrinsic,+_getClass", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=option,*.*,ccstrlist,ControlIntrinsic,+_getClass", "-version") .shouldContain("CompileCommand: ControlIntrinsic *.* const char* ControlIntrinsic") .shouldHaveExitValue(0) .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); - ProcessTools.executeTestJvm("-XX:CompileCommand=option,class,PrintIntrinsics", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=option,class,PrintIntrinsics", "-version") .shouldHaveExitValue(0) .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); // corner case: // PrintIntrinsics could be a valid method name, so it is accepted in the well-formed case. - ProcessTools.executeTestJvm("-XX:CompileCommand=option,class.PrintIntrinsics,PrintIntrinsics", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=option,class.PrintIntrinsics,PrintIntrinsics", "-version") .shouldContain("CompileCommand: PrintIntrinsics class.PrintIntrinsics bool PrintIntrinsics = true") .shouldHaveExitValue(0) .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); // corner case: // _dontinline_* is a valid method pattern, so it should be accepted - ProcessTools.executeTestJvm("-XX:CompileCommand=dontinline,*::dontinline_*", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=dontinline,*::dontinline_*", "-version") .shouldContain("CompileCommand: dontinline *.dontinline_* bool dontinline = true") .shouldHaveExitValue(0) .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); - ProcessTools.executeTestJvm("-XX:CompileCommand=dontinline,*.dontinline", "-version") + ProcessTools.executeTestJava("-XX:CompileCommand=dontinline,*.dontinline", "-version") .shouldContain("CompileCommand: dontinline *.dontinline bool dontinline = true") .shouldHaveExitValue(0) .shouldNotContain("Error: Did not specify any method name") diff --git a/test/hotspot/jtreg/compiler/compilercontrol/parser/HugeDirectiveUtil.java b/test/hotspot/jtreg/compiler/compilercontrol/parser/HugeDirectiveUtil.java index 6db9a995862..d337266dd50 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/parser/HugeDirectiveUtil.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/parser/HugeDirectiveUtil.java @@ -121,7 +121,7 @@ private static List getRandomDescriptors( protected static OutputAnalyzer execute(String fileName) { OutputAnalyzer output; try { - output = ProcessTools.executeTestJvm( + output = ProcessTools.executeTestJava( "-XX:+UnlockDiagnosticVMOptions", "-XX:CompilerDirectivesLimit=1000", "-XX:CompilerDirectivesFile=" + fileName, diff --git a/test/hotspot/jtreg/compiler/compilercontrol/share/scenario/Executor.java b/test/hotspot/jtreg/compiler/compilercontrol/share/scenario/Executor.java index 0111d1e90a1..799fabf9509 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/share/scenario/Executor.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/share/scenario/Executor.java @@ -101,7 +101,7 @@ public List execute() { vmInputArgs.length + vmOptions.size()); System.arraycopy(vmOptions.toArray(), 0, cmds, vmInputArgs.length, vmOptions.size()); - output = ProcessTools.executeTestJvm(cmds); + output = ProcessTools.executeTestJava(cmds); } catch (Throwable thr) { throw new Error("Execution failed: " + thr.getMessage(), thr); } diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java index 4c56daebfb8..ac3a6d9a8c6 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -72,7 +72,7 @@ private boolean isTieredLevelGreaterThan(int level) { * @throws Throwable */ private void testUseAES() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( prepareArguments(prepareBooleanFlag(AESIntrinsicsBase .USE_AES, true))); final String errorMessage = "Case testUseAES failed"; @@ -103,7 +103,7 @@ private void testUseAES() throws Throwable { */ private void testUseAESUseSSE2() throws Throwable { if (Platform.isX86() || Platform.isX64()) { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( prepareArguments(prepareBooleanFlag(AESIntrinsicsBase .USE_AES_INTRINSICS, true), prepareNumericFlag(AESIntrinsicsBase.USE_SSE, 2))); @@ -132,7 +132,7 @@ private void testUseAESUseSSE2() throws Throwable { */ private void testNoUseAESUseSSE2() throws Throwable { if (Platform.isX86() || Platform.isX64()) { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( prepareArguments(prepareBooleanFlag(AESIntrinsicsBase .USE_AES, false), prepareNumericFlag(AESIntrinsicsBase.USE_SSE, 2))); @@ -158,7 +158,7 @@ private void testNoUseAESUseSSE2() throws Throwable { * @throws Throwable */ private void testNoUseAES() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( prepareArguments(prepareBooleanFlag(AESIntrinsicsBase .USE_AES, false))); final String errorMessage = "Case testNoUseAES failed"; @@ -180,7 +180,7 @@ private void testNoUseAES() throws Throwable { * @throws Throwable */ private void testNoUseAESIntrinsic() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( prepareArguments(prepareBooleanFlag(AESIntrinsicsBase .USE_AES_INTRINSICS, false))); final String errorMessage = "Case testNoUseAESIntrinsic failed"; diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java index 03016ea3dd6..fdc8f63f9e0 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -65,7 +65,7 @@ protected void runTestCases() throws Throwable { * @throws Throwable */ private void testUseAESIntrinsics() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( AESIntrinsicsBase.prepareArguments(prepareBooleanFlag( AESIntrinsicsBase.USE_AES_INTRINSICS, true))); final String errorMessage = "Case testUseAESIntrinsics failed"; @@ -89,7 +89,7 @@ private void testUseAESIntrinsics() throws Throwable { * @throws Throwable */ private void testUseAES() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( AESIntrinsicsBase.prepareArguments(prepareBooleanFlag (AESIntrinsicsBase.USE_AES, true))); final String errorMessage = "Case testUseAES failed"; diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestMembarDependencies.java b/test/hotspot/jtreg/compiler/gcbarriers/TestMembarDependencies.java index bbd518c6756..3678691b218 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestMembarDependencies.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestMembarDependencies.java @@ -43,7 +43,7 @@ public class TestMembarDependencies { public static void main(String args[]) throws Exception { if (args.length == 0) { // For debugging, add "-XX:+TraceOptoPipelining" - OutputAnalyzer oa = ProcessTools.executeTestJvm("-XX:+IgnoreUnrecognizedVMOptions", + OutputAnalyzer oa = ProcessTools.executeTestJava("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", "-XX:+PrintOpto", "-XX:CompileCommand=compileonly,compiler.membars.TestMembarDependencies::test*", "-XX:CompileCommand=dontinline,compiler.membars.TestMembarDependencies::test_m1", diff --git a/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java b/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java index 5d2651c3285..0d3c9569c33 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java +++ b/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,10 +46,13 @@ import java.util.Base64; import java.util.Base64.Decoder; import java.util.Base64.Encoder; +import java.util.HexFormat; import java.util.Objects; import java.util.Random; import java.util.Arrays; +import static java.lang.String.format; + import compiler.whitebox.CompilerWhiteBoxTest; import jdk.test.whitebox.code.Compiler; import jtreg.SkippedException; @@ -69,6 +72,8 @@ public static void main(String[] args) throws Exception { warmup(); + length_checks(); + test0(FileType.ASCII, Base64Type.BASIC, Base64.getEncoder(), Base64.getDecoder(),"plain.txt", "baseEncode.txt", iters); test0(FileType.ASCII, Base64Type.URLSAFE, Base64.getUrlEncoder(), Base64.getUrlDecoder(),"plain.txt", "urlEncode.txt", iters); test0(FileType.ASCII, Base64Type.MIME, Base64.getMimeEncoder(), Base64.getMimeDecoder(),"plain.txt", "mimeEncode.txt", iters); @@ -302,4 +307,118 @@ private static final byte getBadBase64Char(Base64Type b64Type) { throw new InternalError("Internal test error: getBadBase64Char called with unknown Base64Type value"); } } + + static final int POSITIONS = 30_000; + static final int BASE_LENGTH = 256; + static final HexFormat HEX_FORMAT = HexFormat.of().withUpperCase().withDelimiter(" "); + + static int[] plainOffsets = new int[POSITIONS + 1]; + static byte[] plainBytes; + static int[] base64Offsets = new int[POSITIONS + 1]; + static byte[] base64Bytes; + + static { + // Set up ByteBuffer with characters to be encoded + int plainLength = 0; + for (int i = 0; i < plainOffsets.length; i++) { + plainOffsets[i] = plainLength; + int positionLength = (BASE_LENGTH + i) % 2048; + plainLength += positionLength; + } + // Put one of each possible byte value into ByteBuffer + plainBytes = new byte[plainLength]; + for (int i = 0; i < plainBytes.length; i++) { + plainBytes[i] = (byte) i; + } + + // Grab various slices of the ByteBuffer and encode them + ByteBuffer plainBuffer = ByteBuffer.wrap(plainBytes); + int base64Length = 0; + for (int i = 0; i < POSITIONS; i++) { + base64Offsets[i] = base64Length; + int offset = plainOffsets[i]; + int length = plainOffsets[i + 1] - offset; + ByteBuffer plainSlice = plainBuffer.slice(offset, length); + base64Length += Base64.getEncoder().encode(plainSlice).remaining(); + } + + // Decode the slices created above and ensure lengths match + base64Offsets[base64Offsets.length - 1] = base64Length; + base64Bytes = new byte[base64Length]; + for (int i = 0; i < POSITIONS; i++) { + int plainOffset = plainOffsets[i]; + ByteBuffer plainSlice = plainBuffer.slice(plainOffset, plainOffsets[i + 1] - plainOffset); + ByteBuffer encodedBytes = Base64.getEncoder().encode(plainSlice); + int base64Offset = base64Offsets[i]; + int expectedLength = base64Offsets[i + 1] - base64Offset; + if (expectedLength != encodedBytes.remaining()) { + throw new IllegalStateException(format("Unexpected length: %s <> %s", encodedBytes.remaining(), expectedLength)); + } + encodedBytes.get(base64Bytes, base64Offset, expectedLength); + } + } + + public static void length_checks() { + decodeAndCheck(); + encodeDecode(); + System.out.println("Test complete, no invalid decodes detected"); + } + + // Use ByteBuffer to cause decode() to use the base + offset form of decode + // Checks for bug reported in JDK-8321599 where padding characters appear + // within the beginning of the ByteBuffer *before* the offset. This caused + // the decoded string length to be off by 1 or 2 bytes. + static void decodeAndCheck() { + for (int i = 0; i < POSITIONS; i++) { + ByteBuffer encodedBytes = base64BytesAtPosition(i); + ByteBuffer decodedBytes = Base64.getDecoder().decode(encodedBytes); + + if (!decodedBytes.equals(plainBytesAtPosition(i))) { + String base64String = base64StringAtPosition(i); + String plainHexString = plainHexStringAtPosition(i); + String decodedHexString = HEX_FORMAT.formatHex(decodedBytes.array(), decodedBytes.arrayOffset() + decodedBytes.position(), decodedBytes.arrayOffset() + decodedBytes.limit()); + throw new IllegalStateException(format("Mismatch for %s\n\nExpected:\n%s\n\nActual:\n%s", base64String, plainHexString, decodedHexString)); + } + } + } + + // Encode strings of lengths 1-1K, decode, and ensure length and contents correct. + // This checks that padding characters are properly handled by decode. + static void encodeDecode() { + String allAs = "A(=)".repeat(128); + for (int i = 1; i <= 512; i++) { + String encStr = Base64.getEncoder().encodeToString(allAs.substring(0, i).getBytes()); + String decStr = new String(Base64.getDecoder().decode(encStr)); + + if ((decStr.length() != allAs.substring(0, i).length()) || + (!Objects.equals(decStr, allAs.substring(0, i))) + ) { + throw new IllegalStateException(format("Mismatch: Expected: %s\n Actual: %s\n", allAs.substring(0, i), decStr)); + } + } + } + + static ByteBuffer plainBytesAtPosition(int position) { + int offset = plainOffsets[position]; + int length = plainOffsets[position + 1] - offset; + return ByteBuffer.wrap(plainBytes, offset, length); + } + + static String plainHexStringAtPosition(int position) { + int offset = plainOffsets[position]; + int length = plainOffsets[position + 1] - offset; + return HEX_FORMAT.formatHex(plainBytes, offset, offset + length); + } + + static String base64StringAtPosition(int position) { + int offset = base64Offsets[position]; + int length = base64Offsets[position + 1] - offset; + return new String(base64Bytes, offset, length, StandardCharsets.UTF_8); + } + + static ByteBuffer base64BytesAtPosition(int position) { + int offset = base64Offsets[position]; + int length = base64Offsets[position + 1] - offset; + return ByteBuffer.wrap(base64Bytes, offset, length); + } } diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/BMITestRunner.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/BMITestRunner.java index 4060bacbfba..159e471e3fc 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/BMITestRunner.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/BMITestRunner.java @@ -146,7 +146,7 @@ public static OutputAnalyzer runTest(Class expr, new Integer(iterations).toString() }); - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm(vmOpts); + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(vmOpts); outputAnalyzer.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseMD5IntrinsicsOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseMD5IntrinsicsOptionOnUnsupportedCPU.java index e9ae2f6c163..cd5933ec951 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseMD5IntrinsicsOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseMD5IntrinsicsOptionOnUnsupportedCPU.java @@ -39,6 +39,7 @@ import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForOtherCPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedAArch64CPU; +import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedRISCV64CPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedX86CPU; import compiler.intrinsics.sha.cli.testcases.UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU; @@ -49,6 +50,8 @@ public static void main(String args[]) throws Throwable { DigestOptionsBase.USE_MD5_INTRINSICS_OPTION, /* checkUseSHA = */ false), new GenericTestCaseForUnsupportedAArch64CPU( DigestOptionsBase.USE_MD5_INTRINSICS_OPTION, /* checkUseSHA = */ false), + new GenericTestCaseForUnsupportedRISCV64CPU( + DigestOptionsBase.USE_MD5_INTRINSICS_OPTION, /* checkUseSHA = */ false), new GenericTestCaseForOtherCPU( DigestOptionsBase.USE_MD5_INTRINSICS_OPTION, /* checkUseSHA = */ false)).test(); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index 6f5149a79ba..26a271949e7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,27 @@ public enum CompilePhase { ITER_GVN_AFTER_VECTOR("Iter GVN after vector box elimination"), BEFORE_BEAUTIFY_LOOPS("Before beautify loops"), AFTER_BEAUTIFY_LOOPS("After beautify loops"), + BEFORE_LOOP_UNROLLING("Before Loop Unrolling"), + AFTER_LOOP_UNROLLING("After Loop Unrolling"), + BEFORE_SPLIT_IF("Before Split-If"), + AFTER_SPLIT_IF("After Split-If"), + BEFORE_LOOP_PREDICATION_IC("Before Loop Predication IC"), + AFTER_LOOP_PREDICATION_IC("After Loop Predication IC"), + BEFORE_LOOP_PREDICATION_RC("Before Loop Predication RC"), + AFTER_LOOP_PREDICATION_RC("After Loop Predication RC"), + BEFORE_PARTIAL_PEELING("Before Partial Peeling"), + AFTER_PARTIAL_PEELING("After Partial Peeling"), + BEFORE_LOOP_PEELING("Before Loop Peeling"), + AFTER_LOOP_PEELING("After Loop Peeling"), + BEFORE_LOOP_UNSWITCHING("Before Loop Unswitching"), + AFTER_LOOP_UNSWITCHING("After Loop Unswitching"), + BEFORE_RANGE_CHECK_ELIMINATION("Before Range Check Elimination"), + AFTER_RANGE_CHECK_ELIMINATION("After Range Check Elimination"), + BEFORE_PRE_MAIN_POST("Before Pre/Main/Post Loops"), + AFTER_PRE_MAIN_POST("After Pre/Main/Post Loops"), + SUPERWORD1_BEFORE_SCHEDULE("Superword 1, Before Schedule"), + SUPERWORD2_BEFORE_OUTPUT("Superword 2, Before Output"), + SUPERWORD3_AFTER_OUTPUT("Superword 3, After Output"), // Match on very first BEFORE_CLOOPS phase (there could be multiple phases for multiple loops in the code). BEFORE_CLOOPS("Before CountedLoop", RegexType.IDEAL_INDEPENDENT, ActionOnRepeat.KEEP_FIRST), AFTER_CLOOPS("After CountedLoop"), @@ -70,6 +91,7 @@ public enum CompilePhase { PHASEIDEALLOOP1("PhaseIdealLoop 1"), PHASEIDEALLOOP2("PhaseIdealLoop 2"), PHASEIDEALLOOP3("PhaseIdealLoop 3"), + BEFORE_CCP1("Before PhaseCCP 1"), CCP1("PhaseCCP 1"), ITER_GVN2("Iter GVN 2"), PHASEIDEALLOOP_ITERATIONS("PhaseIdealLoop iterations"), @@ -79,8 +101,12 @@ public enum CompilePhase { PRINT_IDEAL("PrintIdeal"), BEFORE_MATCHING("Before matching"), MATCHING("After matching", RegexType.MACH), - MACH_ANALYSIS("After mach analysis", RegexType.MACH), GLOBAL_CODE_MOTION("Global code motion", RegexType.MACH), + REGISTER_ALLOCATION("Register Allocation", RegexType.MACH), + BLOCK_ORDERING("Block Ordering", RegexType.MACH), + PEEPHOLE("Peephole", RegexType.MACH), + POSTALLOC_EXPAND("Post-Allocation Expand", RegexType.MACH), + MACH_ANALYSIS("After mach analysis", RegexType.MACH), FINAL_CODE("Final Code", RegexType.MACH), END("End"), diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 5713bb5ef02..81a5b38baa5 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,6 +298,11 @@ public class IRNode { optoOnly(ALLOC_ARRAY_OF, regex); } + public static final String OR = PREFIX + "OR" + POSTFIX; + static { + beforeMatchingNameRegex(OR, "Or(I|L)"); + } + public static final String AND = PREFIX + "AND" + POSTFIX; static { beforeMatchingNameRegex(AND, "And(I|L)"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 8ea1e32cebb..ea149ff23e2 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,6 +135,7 @@ public class TestFramework { "CompileThreshold", "Xmixed", "server", + "AlignVector", "UseAVX", "UseSSE", "UseSVE", diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java index f15d4bec398..cb362b3bbfb 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java @@ -112,7 +112,7 @@ private void prepareVMFlags(Class testClass, List additionalFlags) { private void start() { try { // Run "flag" VM with White Box access to determine the test VM flags and if IR verification should be done. - oa = ProcessTools.executeTestJvm(cmds); + oa = ProcessTools.executeTestJava(cmds); } catch (Exception e) { throw new TestRunException("Failed to execute TestFramework flag VM", e); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 2c63bbe9589..04f8096d969 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -149,7 +149,7 @@ private void start() { ProcessBuilder process = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); try { // Calls 'main' of TestVM to run all specified tests with commands 'cmds'. - // Use executeProcess instead of executeTestJvm as we have already added the JTreg VM and + // Use executeProcess instead of executeTestJava as we have already added the JTreg VM and // Java options in prepareTestVMFlags(). oa = ProcessTools.executeProcess(process); } catch (Exception e) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompilePhaseBlock.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompilePhaseBlock.java index 16cc62f9c57..b97c56a5720 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompilePhaseBlock.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompilePhaseBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * This class represents a single compile phase block of a {@link LoggedMethod}. */ class CompilePhaseBlock { - public static final String SAFEPOINT_WHILE_PRINTING_MESSAGE = ""; /** * Dummy object for a block that we do not need to parse. @@ -38,11 +37,6 @@ class CompilePhaseBlock { private final CompilePhase compilePhase; private final StringBuilder builder; - /** - * Stores an incomplete line that was interrupted by a safepoint. - * Needs to be merged with the immediately following line. - */ - private String incompleteLine = ""; public CompilePhaseBlock(CompilePhase compilePhase) { this.compilePhase = compilePhase; @@ -92,35 +86,14 @@ public static boolean isBlockEndLine(String line) { } public void addLine(String line) { - line = mergeWithIncompleteLine(line); - if (line.endsWith(SAFEPOINT_WHILE_PRINTING_MESSAGE)) { - line = removeSafepointMessage(line); - incompleteLine = line; - } else { - appendLine(line); - } - } - - private String mergeWithIncompleteLine(String line) { - if (!incompleteLine.isEmpty()) { - line = incompleteLine + line; - incompleteLine = ""; - } - return line; - } + builder.append(escapeXML(line)).append(System.lineSeparator()); - private static String removeSafepointMessage(String line) { - return line.substring(0, line.lastIndexOf(SAFEPOINT_WHILE_PRINTING_MESSAGE)); } public String content() { return builder.toString(); } - private void appendLine(String line) { - builder.append(escapeXML(line)).append(System.lineSeparator()); - } - private static String escapeXML(String line) { if (line.contains("&")) { line = line.replace("<", "<"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/State.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/State.java index 75d6b060cb2..49f25674dbf 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/State.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/State.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,6 @@ * This class holds the current state of the parsing of the hotspot_pid* file. */ class State { - private final WriterThreads writerThreads; - private WriterThread writerThread; private final CompileQueueMessages compileQueueMessages; private final LoggedMethods loggedMethods; private LoggedMethod loggedMethod = LoggedMethod.DONT_CARE; @@ -38,7 +36,6 @@ class State { public State(String testClassName, TestMethods testMethods) { this.compileQueueMessages = new CompileQueueMessages(testClassName, testMethods); this.loggedMethods = new LoggedMethods(); - this.writerThreads = new WriterThreads(); } public LoggedMethods loggedMethods() { @@ -46,9 +43,7 @@ public LoggedMethods loggedMethods() { } public void update(String line) { - if (WriterThread.isWriterThreadLine(line)) { - processWriterThreadLine(line); - } else if (compileQueueMessages.isTestMethodQueuedLine(line)) { + if (compileQueueMessages.isTestMethodQueuedLine(line)) { processCompileQueueLine(line); } else if (CompilePhaseBlock.isBlockStartLine(line)) { processBlockStartLine(line); @@ -59,15 +54,6 @@ public void update(String line) { } } - private void processWriterThreadLine(String line) { - if (loggedMethod.hasActiveBlock()) { - // The current compile phase block was interrupted due to a safepoint. Save and restore later. - writerThread.saveLoggedMethod(loggedMethod); - } - writerThread = writerThreads.parse(line); - loggedMethod = writerThread.restoreLoggedMethod(); - } - private void processCompileQueueLine(String line) { String methodName = compileQueueMessages.parse(line); loggedMethods.registerMethod(methodName); diff --git a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java index a971c947ff4..effbbbe46bd 100644 --- a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java +++ b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java @@ -59,9 +59,10 @@ public static void main (String args[]) { private static void check(boolean enabled) { OutputAnalyzer oa; try { - oa = ProcessTools.executeTestJvm("-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", - "-XX:" + (enabled ? "+" : "-") + "UseCountedLoopSafepoints", - "-XX:+WhiteBoxAPI", + oa = ProcessTools.executeTestJava( + "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", + "-XX:" + (enabled ? "+" : "-") + "UseCountedLoopSafepoints", + "-XX:+WhiteBoxAPI", "-XX:-Inline", "-Xbatch", "-XX:+PrintIdeal", "-XX:LoopUnrollLimit=0", "-XX:CompileOnly=" + UseCountedLoopSafepoints.class.getName() + "::testMethod", UseCountedLoopSafepoints.class.getName()); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java new file mode 100644 index 00000000000..fe873770ab4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java @@ -0,0 +1,1479 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import jdk.test.whitebox.WhiteBox; +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Array; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; +import java.nio.ByteOrder; + +/* + * @test id=NoAlignVector + * @bug 8310190 + * @summary Test AlignVector with various loop init, stride, scale, invar, etc. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver compiler.loopopts.superword.TestAlignVector NoAlignVector + */ + +/* + * @test id=AlignVector + * @bug 8310190 + * @summary Test AlignVector with various loop init, stride, scale, invar, etc. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver compiler.loopopts.superword.TestAlignVector AlignVector + */ + +/* + * @test id=VerifyAlignVector + * @bug 8310190 + * @summary Test AlignVector with various loop init, stride, scale, invar, etc. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver compiler.loopopts.superword.TestAlignVector VerifyAlignVector + */ + +public class TestAlignVector { + static int RANGE = 1024*8; + static int RANGE_FINAL = 1024*8; + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static final Random RANDOM = Utils.getRandomInstance(); + + // Inputs + byte[] aB; + byte[] bB; + byte mB = (byte)31; + short[] aS; + short[] bS; + short mS = (short)0xF0F0; + int[] aI; + int[] bI; + int mI = 0xF0F0F0F0; + long[] aL; + long[] bL; + long mL = 0xF0F0F0F0F0F0F0F0L; + + // List of tests + Map tests = new HashMap(); + + // List of gold, the results from the first run before compilation + Map golds = new HashMap(); + + interface TestFunction { + Object[] run(); + } + + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestAlignVector.class); + framework.addFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "-XX:LoopUnrollLimit=250"); + + switch (args[0]) { + case "NoAlignVector" -> { framework.addFlags("-XX:-AlignVector"); } + case "AlignVector" -> { framework.addFlags("-XX:+AlignVector"); } + case "VerifyAlignVector" -> { framework.addFlags("-XX:+AlignVector", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+VerifyAlignVector"); } + default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } + } + framework.start(); + } + + public TestAlignVector() { + // Generate input once + aB = generateB(); + bB = generateB(); + aS = generateS(); + bS = generateS(); + aI = generateI(); + bI = generateI(); + aL = generateL(); + bL = generateL(); + + // Add all tests to list + tests.put("test0", () -> { return test0(aB.clone(), bB.clone(), mB); }); + tests.put("test1", () -> { return test1(aB.clone(), bB.clone(), mB); }); + tests.put("test2", () -> { return test2(aB.clone(), bB.clone(), mB); }); + tests.put("test3", () -> { return test3(aB.clone(), bB.clone(), mB); }); + tests.put("test4", () -> { return test4(aB.clone(), bB.clone(), mB); }); + tests.put("test5", () -> { return test5(aB.clone(), bB.clone(), mB, 0); }); + tests.put("test6", () -> { return test6(aB.clone(), bB.clone(), mB); }); + tests.put("test7", () -> { return test7(aS.clone(), bS.clone(), mS); }); + tests.put("test8", () -> { return test8(aB.clone(), bB.clone(), mB, 0); }); + tests.put("test8", () -> { return test8(aB.clone(), bB.clone(), mB, 1); }); + tests.put("test9", () -> { return test9(aB.clone(), bB.clone(), mB); }); + + tests.put("test10a", () -> { return test10a(aB.clone(), bB.clone(), mB); }); + tests.put("test10b", () -> { return test10b(aB.clone(), bB.clone(), mB); }); + tests.put("test10c", () -> { return test10c(aS.clone(), bS.clone(), mS); }); + tests.put("test10d", () -> { return test10d(aS.clone(), bS.clone(), mS); }); + + tests.put("test11aB", () -> { return test11aB(aB.clone(), bB.clone(), mB); }); + tests.put("test11aS", () -> { return test11aS(aS.clone(), bS.clone(), mS); }); + tests.put("test11aI", () -> { return test11aI(aI.clone(), bI.clone(), mI); }); + tests.put("test11aL", () -> { return test11aL(aL.clone(), bL.clone(), mL); }); + + tests.put("test11bB", () -> { return test11bB(aB.clone(), bB.clone(), mB); }); + tests.put("test11bS", () -> { return test11bS(aS.clone(), bS.clone(), mS); }); + tests.put("test11bI", () -> { return test11bI(aI.clone(), bI.clone(), mI); }); + tests.put("test11bL", () -> { return test11bL(aL.clone(), bL.clone(), mL); }); + + tests.put("test11cB", () -> { return test11cB(aB.clone(), bB.clone(), mB); }); + tests.put("test11cS", () -> { return test11cS(aS.clone(), bS.clone(), mS); }); + tests.put("test11cI", () -> { return test11cI(aI.clone(), bI.clone(), mI); }); + tests.put("test11cL", () -> { return test11cL(aL.clone(), bL.clone(), mL); }); + + tests.put("test11dB", () -> { return test11dB(aB.clone(), bB.clone(), mB, 0); }); + tests.put("test11dS", () -> { return test11dS(aS.clone(), bS.clone(), mS, 0); }); + tests.put("test11dI", () -> { return test11dI(aI.clone(), bI.clone(), mI, 0); }); + tests.put("test11dL", () -> { return test11dL(aL.clone(), bL.clone(), mL, 0); }); + + tests.put("test12", () -> { return test12(aB.clone(), bB.clone(), mB); }); + + tests.put("test13aIL", () -> { return test13aIL(aI.clone(), aL.clone()); }); + tests.put("test13aIB", () -> { return test13aIB(aI.clone(), aB.clone()); }); + tests.put("test13aIS", () -> { return test13aIS(aI.clone(), aS.clone()); }); + tests.put("test13aBSIL", () -> { return test13aBSIL(aB.clone(), aS.clone(), aI.clone(), aL.clone()); }); + + tests.put("test13bIL", () -> { return test13bIL(aI.clone(), aL.clone()); }); + tests.put("test13bIB", () -> { return test13bIB(aI.clone(), aB.clone()); }); + tests.put("test13bIS", () -> { return test13bIS(aI.clone(), aS.clone()); }); + tests.put("test13bBSIL", () -> { return test13bBSIL(aB.clone(), aS.clone(), aI.clone(), aL.clone()); }); + + tests.put("test14aB", () -> { return test14aB(aB.clone()); }); + tests.put("test14bB", () -> { return test14bB(aB.clone()); }); + tests.put("test14cB", () -> { return test14cB(aB.clone()); }); + + tests.put("test15aB", () -> { return test15aB(aB.clone()); }); + tests.put("test15bB", () -> { return test15bB(aB.clone()); }); + tests.put("test15cB", () -> { return test15cB(aB.clone()); }); + + tests.put("test16a", () -> { return test16a(aB.clone(), aS.clone()); }); + tests.put("test16b", () -> { return test16b(aB.clone()); }); + + tests.put("test17a", () -> { return test17a(aL.clone()); }); + tests.put("test17b", () -> { return test17b(aL.clone()); }); + tests.put("test17c", () -> { return test17c(aL.clone()); }); + tests.put("test17d", () -> { return test17d(aL.clone()); }); + + tests.put("test18a", () -> { return test18a(aB.clone(), aI.clone()); }); + tests.put("test18b", () -> { return test18b(aB.clone(), aI.clone()); }); + + tests.put("test19", () -> { return test19(aI.clone(), bI.clone()); }); + tests.put("test20", () -> { return test20(aB.clone()); }); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + Object[] gold = test.run(); + golds.put(name, gold); + } + } + + @Warmup(100) + @Run(test = {"test0", + "test1", + "test2", + "test3", + "test4", + "test5", + "test6", + "test7", + "test8", + "test9", + "test10a", + "test10b", + "test10c", + "test10d", + "test11aB", + "test11aS", + "test11aI", + "test11aL", + "test11bB", + "test11bS", + "test11bI", + "test11bL", + "test11cB", + "test11cS", + "test11cI", + "test11cL", + "test11dB", + "test11dS", + "test11dI", + "test11dL", + "test12", + "test13aIL", + "test13aIB", + "test13aIS", + "test13aBSIL", + "test13bIL", + "test13bIB", + "test13bIS", + "test13bBSIL", + "test14aB", + "test14bB", + "test14cB", + "test15aB", + "test15bB", + "test15cB", + "test16a", + "test16b", + "test17a", + "test17b", + "test17c", + "test17d", + "test18a", + "test18b", + "test19", + "test20"}) + public void runTests() { + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object[] gold = golds.get(name); + // Compute new result + Object[] result = test.run(); + // Compare gold and new result + verify(name, gold, result); + } + } + + static byte[] generateB() { + byte[] a = new byte[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = (byte)RANDOM.nextInt(); + } + return a; + } + + static short[] generateS() { + short[] a = new short[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = (short)RANDOM.nextInt(); + } + return a; + } + + static int[] generateI() { + int[] a = new int[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextInt(); + } + return a; + } + + static long[] generateL() { + long[] a = new long[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextLong(); + } + return a; + } + + static void verify(String name, Object[] gold, Object[] result) { + if (gold.length != result.length) { + throw new RuntimeException("verify " + name + ": not the same number of outputs: gold.length = " + + gold.length + ", result.length = " + result.length); + } + for (int i = 0; i < gold.length; i++) { + Object g = gold[i]; + Object r = result[i]; + if (g.getClass() != r.getClass() || !g.getClass().isArray() || !r.getClass().isArray()) { + throw new RuntimeException("verify " + name + ": must both be array of same type:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + if (g == r) { + throw new RuntimeException("verify " + name + ": should be two separate arrays (with identical content):" + + " gold[" + i + "] == result[" + i + "]"); + } + if (Array.getLength(g) != Array.getLength(r)) { + throw new RuntimeException("verify " + name + ": arrays must have same length:" + + " gold[" + i + "].length = " + Array.getLength(g) + + " result[" + i + "].length = " + Array.getLength(r)); + } + Class c = g.getClass().getComponentType(); + if (c == byte.class) { + verifyB(name, i, (byte[])g, (byte[])r); + } else if (c == short.class) { + verifyS(name, i, (short[])g, (short[])r); + } else if (c == int.class) { + verifyI(name, i, (int[])g, (int[])r); + } else if (c == long.class) { + verifyL(name, i, (long[])g, (long[])r); + } else { + throw new RuntimeException("verify " + name + ": array type not supported for verify:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + } + } + + static void verifyB(String name, int i, byte[] g, byte[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyS(String name, int i, short[] g, short[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyI(String name, int i, int[] g, int[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyL(String name, int i, long[] g, long[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test0(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE; i+=8) { + // Safe to vectorize with AlignVector + b[i+0] = (byte)(a[i+0] & mask); // offset 0, align 0 + b[i+1] = (byte)(a[i+1] & mask); + b[i+2] = (byte)(a[i+2] & mask); + b[i+3] = (byte)(a[i+3] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.AND_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test1(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE; i+=8) { + // Safe to vectorize with AlignVector + b[i+0] = (byte)(a[i+0] & mask); // offset 0, align 0 + b[i+1] = (byte)(a[i+1] & mask); + b[i+2] = (byte)(a[i+2] & mask); + b[i+3] = (byte)(a[i+3] & mask); + b[i+4] = (byte)(a[i+4] & mask); + b[i+5] = (byte)(a[i+5] & mask); + b[i+6] = (byte)(a[i+6] & mask); + b[i+7] = (byte)(a[i+7] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test2(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE; i+=8) { + // Cannot align with AlignVector: 3 + x * 8 % 8 = 3 + b[i+3] = (byte)(a[i+3] & mask); // at alignment 3 + b[i+4] = (byte)(a[i+4] & mask); + b[i+5] = (byte)(a[i+5] & mask); + b[i+6] = (byte)(a[i+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test3(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE; i+=8) { + // Cannot align with AlignVector: 3 + x * 8 % 8 = 3 + + // Problematic for AlignVector + b[i+0] = (byte)(a[i+0] & mask); // best_memref, align 0 + + b[i+3] = (byte)(a[i+3] & mask); // pack at offset 3 bytes + b[i+4] = (byte)(a[i+4] & mask); + b[i+5] = (byte)(a[i+5] & mask); + b[i+6] = (byte)(a[i+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=16"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_8, "= 0",// unaligned + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_8, "= 0",// unaligned + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">=16"}) + static Object[] test4(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE/16; i++) { + // Problematic for AlignVector + b[i*16 + 0 ] = (byte)(a[i*16 + 0 ] & mask); // 4 pack, 0 aligned + b[i*16 + 1 ] = (byte)(a[i*16 + 1 ] & mask); + b[i*16 + 2 ] = (byte)(a[i*16 + 2 ] & mask); + b[i*16 + 3 ] = (byte)(a[i*16 + 3 ] & mask); + + b[i*16 + 5 ] = (byte)(a[i*16 + 5 ] & mask); // 8 pack, 5 aligned + b[i*16 + 6 ] = (byte)(a[i*16 + 6 ] & mask); + b[i*16 + 7 ] = (byte)(a[i*16 + 7 ] & mask); + b[i*16 + 8 ] = (byte)(a[i*16 + 8 ] & mask); + b[i*16 + 9 ] = (byte)(a[i*16 + 9 ] & mask); + b[i*16 + 10] = (byte)(a[i*16 + 10] & mask); + b[i*16 + 11] = (byte)(a[i*16 + 11] & mask); + b[i*16 + 12] = (byte)(a[i*16 + 12] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test5(byte[] a, byte[] b, byte mask, int inv) { + for (int i = 0; i < RANGE; i+=8) { + // Cannot align with AlignVector because of invariant + b[i+inv+0] = (byte)(a[i+inv+0] & mask); + + b[i+inv+3] = (byte)(a[i+inv+3] & mask); + b[i+inv+4] = (byte)(a[i+inv+4] & mask); + b[i+inv+5] = (byte)(a[i+inv+5] & mask); + b[i+inv+6] = (byte)(a[i+inv+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test6(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE/8; i+=2) { + // Cannot align with AlignVector because offset is odd + b[i*4+0] = (byte)(a[i*4+0] & mask); + + b[i*4+3] = (byte)(a[i*4+3] & mask); + b[i*4+4] = (byte)(a[i*4+4] & mask); + b[i*4+5] = (byte)(a[i*4+5] & mask); + b[i*4+6] = (byte)(a[i*4+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VS, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=16"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_S, "= 0", + IRNode.AND_VS, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test7(short[] a, short[] b, short mask) { + for (int i = 0; i < RANGE/8; i+=2) { + // Cannot align with AlignVector because offset is odd + b[i*4+0] = (short)(a[i*4+0] & mask); + + b[i*4+3] = (short)(a[i*4+3] & mask); + b[i*4+4] = (short)(a[i*4+4] & mask); + b[i*4+5] = (short)(a[i*4+5] & mask); + b[i*4+6] = (short)(a[i*4+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test8(byte[] a, byte[] b, byte mask, int init) { + for (int i = init; i < RANGE; i+=8) { + // Cannot align with AlignVector because of invariant (variable init becomes invar) + b[i+0] = (byte)(a[i+0] & mask); + + b[i+3] = (byte)(a[i+3] & mask); + b[i+4] = (byte)(a[i+4] & mask); + b[i+5] = (byte)(a[i+5] & mask); + b[i+6] = (byte)(a[i+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test9(byte[] a, byte[] b, byte mask) { + // known non-zero init value does not affect offset, but has implicit effect on iv + for (int i = 13; i < RANGE-8; i+=8) { + b[i+0] = (byte)(a[i+0] & mask); + + b[i+3] = (byte)(a[i+3] & mask); + b[i+4] = (byte)(a[i+4] & mask); + b[i+5] = (byte)(a[i+5] & mask); + b[i+6] = (byte)(a[i+6] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test10a(byte[] a, byte[] b, byte mask) { + // This is not alignable with pre-loop, because of odd init. + for (int i = 3; i < RANGE-8; i+=8) { + b[i+0] = (byte)(a[i+0] & mask); + b[i+1] = (byte)(a[i+1] & mask); + b[i+2] = (byte)(a[i+2] & mask); + b[i+3] = (byte)(a[i+3] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VB, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=8"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test10b(byte[] a, byte[] b, byte mask) { + // This is not alignable with pre-loop, because of odd init. + // Seems not correctly handled. + for (int i = 13; i < RANGE-8; i+=8) { + b[i+0] = (byte)(a[i+0] & mask); + b[i+1] = (byte)(a[i+1] & mask); + b[i+2] = (byte)(a[i+2] & mask); + b[i+3] = (byte)(a[i+3] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VS, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=16"}) + @IR(counts = {IRNode.LOAD_VECTOR_S, "= 0", + IRNode.AND_VS, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test10c(short[] a, short[] b, short mask) { + // This is not alignable with pre-loop, because of odd init. + // Seems not correctly handled with MaxVectorSize >= 32. + for (int i = 13; i < RANGE-8; i+=8) { + b[i+0] = (short)(a[i+0] & mask); + b[i+1] = (short)(a[i+1] & mask); + b[i+2] = (short)(a[i+2] & mask); + b[i+3] = (short)(a[i+3] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VS, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test10d(short[] a, short[] b, short mask) { + for (int i = 13; i < RANGE-16; i+=8) { + // init + offset -> aligned + b[i+0+3] = (short)(a[i+0+3] & mask); + b[i+1+3] = (short)(a[i+1+3] & mask); + b[i+2+3] = (short)(a[i+2+3] & mask); + b[i+3+3] = (short)(a[i+3+3] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.AND_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11aB(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE; i++) { + // always alignable + b[i+0] = (byte)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.AND_VS, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11aS(short[] a, short[] b, short mask) { + for (int i = 0; i < RANGE; i++) { + // always alignable + b[i+0] = (short)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.AND_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11aI(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i++) { + // always alignable + b[i+0] = (int)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.AND_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11aL(long[] a, long[] b, long mask) { + for (int i = 0; i < RANGE; i++) { + // always alignable + b[i+0] = (long)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.AND_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11bB(byte[] a, byte[] b, byte mask) { + for (int i = 1; i < RANGE; i++) { + // always alignable + b[i+0] = (byte)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.AND_VS, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11bS(short[] a, short[] b, short mask) { + for (int i = 1; i < RANGE; i++) { + // always alignable + b[i+0] = (short)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.AND_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11bI(int[] a, int[] b, int mask) { + for (int i = 1; i < RANGE; i++) { + // always alignable + b[i+0] = (int)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.AND_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11bL(long[] a, long[] b, long mask) { + for (int i = 1; i < RANGE; i++) { + // always alignable + b[i+0] = (long)(a[i+0] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.AND_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test11cB(byte[] a, byte[] b, byte mask) { + for (int i = 1; i < RANGE-1; i++) { + // 1 byte offset -> not alignable with AlignVector + b[i+0] = (byte)(a[i+1] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.AND_VS, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + @IR(counts = {IRNode.LOAD_VECTOR_S, "= 0", + IRNode.AND_VS, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test11cS(short[] a, short[] b, short mask) { + for (int i = 1; i < RANGE-1; i++) { + // 2 byte offset -> not alignable with AlignVector + b[i+0] = (short)(a[i+1] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.AND_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.AND_VI, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test11cI(int[] a, int[] b, int mask) { + for (int i = 1; i < RANGE-1; i++) { + // 4 byte offset -> not alignable with AlignVector + b[i+0] = (int)(a[i+1] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.AND_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11cL(long[] a, long[] b, long mask) { + for (int i = 1; i < RANGE-1; i++) { + // always alignable (8 byte offset) + b[i+0] = (long)(a[i+1] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.AND_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11dB(byte[] a, byte[] b, byte mask, int invar) { + for (int i = 0; i < RANGE; i++) { + b[i+0+invar] = (byte)(a[i+0+invar] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.AND_VS, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11dS(short[] a, short[] b, short mask, int invar) { + for (int i = 0; i < RANGE; i++) { + b[i+0+invar] = (short)(a[i+0+invar] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.AND_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11dI(int[] a, int[] b, int mask, int invar) { + for (int i = 0; i < RANGE; i++) { + b[i+0+invar] = (int)(a[i+0+invar] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.AND_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test11dL(long[] a, long[] b, long mask, int invar) { + for (int i = 0; i < RANGE; i++) { + b[i+0+invar] = (long)(a[i+0+invar] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.AND_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test12(byte[] a, byte[] b, byte mask) { + for (int i = 0; i < RANGE/16; i++) { + // Currently does not vectorize at all + b[i*6 + 0 ] = (byte)(a[i*6 + 0 ] & mask); + b[i*6 + 1 ] = (byte)(a[i*6 + 1 ] & mask); + b[i*6 + 2 ] = (byte)(a[i*6 + 2 ] & mask); + b[i*6 + 3 ] = (byte)(a[i*6 + 3 ] & mask); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VL, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true"}) + // require avx to ensure vectors are larger than what unrolling produces + static Object[] test13aIL(int[] a, long[] b) { + for (int i = 0; i < RANGE; i++) { + a[i]++; + b[i]++; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test13aIB(int[] a, byte[] b) { + for (int i = 0; i < RANGE; i++) { + a[i]++; + b[i]++; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.LOAD_VECTOR_S, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.ADD_VS, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test13aIS(int[] a, short[] b) { + for (int i = 0; i < RANGE; i++) { + a[i]++; + b[i]++; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.LOAD_VECTOR_L, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.ADD_VS, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.ADD_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test13aBSIL(byte[] a, short[] b, int[] c, long[] d) { + for (int i = 0; i < RANGE; i++) { + a[i]++; + b[i]++; + c[i]++; + d[i]++; + } + return new Object[]{ a, b, c, d }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VL, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true"}) + // require avx to ensure vectors are larger than what unrolling produces + static Object[] test13bIL(int[] a, long[] b) { + for (int i = 1; i < RANGE; i++) { + a[i]++; + b[i]++; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test13bIB(int[] a, byte[] b) { + for (int i = 1; i < RANGE; i++) { + a[i]++; + b[i]++; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.LOAD_VECTOR_S, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.ADD_VS, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test13bIS(int[] a, short[] b) { + for (int i = 1; i < RANGE; i++) { + a[i]++; + b[i]++; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.LOAD_VECTOR_L, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.ADD_VS, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.ADD_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + static Object[] test13bBSIL(byte[] a, short[] b, int[] c, long[] d) { + for (int i = 1; i < RANGE; i++) { + a[i]++; + b[i]++; + c[i]++; + d[i]++; + } + return new Object[]{ a, b, c, d }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.ADD_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test14aB(byte[] a) { + // non-power-of-2 stride + for (int i = 0; i < RANGE-20; i+=9) { + a[i+0]++; + a[i+1]++; + a[i+2]++; + a[i+3]++; + a[i+4]++; + a[i+5]++; + a[i+6]++; + a[i+7]++; + a[i+8]++; + a[i+9]++; + a[i+10]++; + a[i+11]++; + a[i+12]++; + a[i+13]++; + a[i+14]++; + a[i+15]++; + } + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.ADD_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test14bB(byte[] a) { + // non-power-of-2 stride + for (int i = 0; i < RANGE-20; i+=3) { + a[i+0]++; + a[i+1]++; + a[i+2]++; + a[i+3]++; + a[i+4]++; + a[i+5]++; + a[i+6]++; + a[i+7]++; + a[i+8]++; + a[i+9]++; + a[i+10]++; + a[i+11]++; + a[i+12]++; + a[i+13]++; + a[i+14]++; + a[i+15]++; + } + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}) + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.ADD_VB, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test14cB(byte[] a) { + // non-power-of-2 stride + for (int i = 0; i < RANGE-20; i+=5) { + a[i+0]++; + a[i+1]++; + a[i+2]++; + a[i+3]++; + a[i+4]++; + a[i+5]++; + a[i+6]++; + a[i+7]++; + a[i+8]++; + a[i+9]++; + a[i+10]++; + a[i+11]++; + a[i+12]++; + a[i+13]++; + a[i+14]++; + a[i+15]++; + } + return new Object[]{ a }; + } + + @Test + // IR rules difficult because of modulo wrapping with offset after peeling. + static Object[] test15aB(byte[] a) { + // non-power-of-2 scale + for (int i = 0; i < RANGE/64-20; i++) { + a[53*i+0]++; + a[53*i+1]++; + a[53*i+2]++; + a[53*i+3]++; + a[53*i+4]++; + a[53*i+5]++; + a[53*i+6]++; + a[53*i+7]++; + a[53*i+8]++; + a[53*i+9]++; + a[53*i+10]++; + a[53*i+11]++; + a[53*i+12]++; + a[53*i+13]++; + a[53*i+14]++; + a[53*i+15]++; + } + return new Object[]{ a }; + } + + @Test + // IR rules difficult because of modulo wrapping with offset after peeling. + static Object[] test15bB(byte[] a) { + // non-power-of-2 scale + for (int i = 0; i < RANGE/64-20; i++) { + a[25*i+0]++; + a[25*i+1]++; + a[25*i+2]++; + a[25*i+3]++; + a[25*i+4]++; + a[25*i+5]++; + a[25*i+6]++; + a[25*i+7]++; + a[25*i+8]++; + a[25*i+9]++; + a[25*i+10]++; + a[25*i+11]++; + a[25*i+12]++; + a[25*i+13]++; + a[25*i+14]++; + a[25*i+15]++; + } + return new Object[]{ a }; + } + + @Test + // IR rules difficult because of modulo wrapping with offset after peeling. + static Object[] test15cB(byte[] a) { + // non-power-of-2 scale + for (int i = 0; i < RANGE/64-20; i++) { + a[19*i+0]++; + a[19*i+1]++; + a[19*i+2]++; + a[19*i+3]++; + a[19*i+4]++; + a[19*i+5]++; + a[19*i+6]++; + a[19*i+7]++; + a[19*i+8]++; + a[19*i+9]++; + a[19*i+10]++; + a[19*i+11]++; + a[19*i+12]++; + a[19*i+13]++; + a[19*i+14]++; + a[19*i+15]++; + } + return new Object[]{ a }; + } + + @Test + static Object[] test16a(byte[] a, short[] b) { + // infinite loop issues + for (int i = 0; i < RANGE/2-20; i++) { + a[2*i+0]++; + a[2*i+1]++; + a[2*i+2]++; + a[2*i+3]++; + a[2*i+4]++; + a[2*i+5]++; + a[2*i+6]++; + a[2*i+7]++; + a[2*i+8]++; + a[2*i+9]++; + a[2*i+10]++; + a[2*i+11]++; + a[2*i+12]++; + a[2*i+13]++; + a[2*i+14]++; + + b[2*i+0]++; + b[2*i+1]++; + b[2*i+2]++; + b[2*i+3]++; + } + return new Object[]{ a, b }; + } + + @Test + static Object[] test16b(byte[] a) { + // infinite loop issues + for (int i = 0; i < RANGE/2-20; i++) { + a[2*i+0]++; + a[2*i+1]++; + a[2*i+2]++; + a[2*i+3]++; + a[2*i+4]++; + a[2*i+5]++; + a[2*i+6]++; + a[2*i+7]++; + a[2*i+8]++; + a[2*i+9]++; + a[2*i+10]++; + a[2*i+11]++; + a[2*i+12]++; + a[2*i+13]++; + a[2*i+14]++; + } + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.ADD_VL, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test17a(long[] a) { + // Unsafe: vectorizes with profiling (not xcomp) + for (int i = 0; i < RANGE; i++) { + int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i; + long v = UNSAFE.getLongUnaligned(a, adr); + UNSAFE.putLongUnaligned(a, adr, v + 1); + } + return new Object[]{ a }; + } + + @Test + // Difficult to write good IR rule. Modulo calculus overflow can create non-power-of-2 packs. + static Object[] test17b(long[] a) { + // Not alignable + for (int i = 0; i < RANGE-1; i++) { + int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1; + long v = UNSAFE.getLongUnaligned(a, adr); + UNSAFE.putLongUnaligned(a, adr, v + 1); + } + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.ADD_VL, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static Object[] test17c(long[] a) { + // Unsafe: aligned vectorizes + for (int i = 0; i < RANGE-1; i+=4) { + int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i; + long v0 = UNSAFE.getLongUnaligned(a, adr + 0); + long v1 = UNSAFE.getLongUnaligned(a, adr + 8); + UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1); + UNSAFE.putLongUnaligned(a, adr + 8, v1 + 1); + } + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.ADD_VL, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"avx512", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">=64"}) + // Ensure vector width is large enough to fit 64 byte for longs: + // The offsets are: 25, 33, 57, 65 + // In modulo 32: 25, 1, 25, 1 -> does not vectorize + // In modulo 64: 25, 33, 57, 1 -> at least first pair vectorizes + // This problem is because we compute modulo vector width in memory_alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "= 0", + IRNode.ADD_VL, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}) + static Object[] test17d(long[] a) { + // Not alignable + for (int i = 0; i < RANGE-1; i+=4) { + int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1; + long v0 = UNSAFE.getLongUnaligned(a, adr + 0); + long v1 = UNSAFE.getLongUnaligned(a, adr + 8); + UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1); + UNSAFE.putLongUnaligned(a, adr + 8, v1 + 1); + } + return new Object[]{ a }; + } + + @Test + static Object[] test18a(byte[] a, int[] b) { + // scale = 0 --> no iv + for (int i = 0; i < RANGE; i++) { + a[0] = 1; + b[i] = 2; + a[1] = 1; + } + return new Object[]{ a, b }; + } + + @Test + static Object[] test18b(byte[] a, int[] b) { + // scale = 0 --> no iv + for (int i = 0; i < RANGE; i++) { + a[1] = 1; + b[i] = 2; + a[2] = 1; + } + return new Object[]{ a, b }; + } + + @Test + static Object[] test19(int[] a, int[] b) { + for (int i = 5000; i > 0; i--) { + a[RANGE_FINAL - i] = b[RANGE_FINAL - i]; + } + return new Object[]{ a, b }; + } + + @Test + static Object[] test20(byte[] a) { + // Example where it is easy to pass alignment check, + // but used to fail the alignment calculation + for (int i = 1; i < RANGE/2-50; i++) { + a[2*i+0+30]++; + a[2*i+1+30]++; + a[2*i+2+30]++; + a[2*i+3+30]++; + } + return new Object[]{ a }; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java new file mode 100644 index 00000000000..478cfbcb2c5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java @@ -0,0 +1,1353 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Vanilla + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Do not force alignment. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +/* + * @test id=VerifyAlignVector + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Verify AlignVector. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+AlignVector -XX:+VerifyAlignVector + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +/* + * @test id=VerifyAlignVector-Align16 + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Verify AlignVector. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @requires vm.bits == 64 + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+AlignVector -XX:+VerifyAlignVector + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * -XX:ObjectAlignmentInBytes=16 + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +/* + * @test id=VerifyAlignVector-NoTieredCompilation-Xbatch + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Verify AlignVector. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+AlignVector -XX:+VerifyAlignVector + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * -XX:-TieredCompilation -Xbatch + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +package compiler.loopopts.superword; + +import java.lang.reflect.Array; +import java.util.Map; +import java.util.HashMap; +import java.lang.invoke.*; +import java.util.Random; +import jdk.test.lib.Utils; +import jdk.internal.misc.Unsafe; + +public class TestAlignVectorFuzzer { + static final int ITERATIONS_MAX = 5; // time allowance may lead to fewer iterations + static final int RANGE_CON = 1024 * 8; + static int ZERO = 0; + + private static final Random random = Utils.getRandomInstance(); + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + interface TestFunction { + Object[] run(); + } + + // Setup for variable compile-time constants: + private static final CallSite INIT_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite LIMIT_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite STRIDE_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite SCALE_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite OFFSET1_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite OFFSET2_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite OFFSET3_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final MethodHandle INIT_MH = INIT_CS.dynamicInvoker(); + private static final MethodHandle LIMIT_MH = LIMIT_CS.dynamicInvoker(); + private static final MethodHandle STRIDE_MH = STRIDE_CS.dynamicInvoker(); + private static final MethodHandle SCALE_MH = SCALE_CS.dynamicInvoker(); + private static final MethodHandle OFFSET1_MH = OFFSET1_CS.dynamicInvoker(); + private static final MethodHandle OFFSET2_MH = OFFSET2_CS.dynamicInvoker(); + private static final MethodHandle OFFSET3_MH = OFFSET3_CS.dynamicInvoker(); + + // Toggle if init, limit and offset are constants or variables + private static final CallSite INIT_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite LIMIT_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite OFFSET1_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite OFFSET2_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite OFFSET3_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final MethodHandle INIT_IS_CON_MH = INIT_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle LIMIT_IS_CON_MH = LIMIT_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle OFFSET1_IS_CON_MH = OFFSET1_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle OFFSET2_IS_CON_MH = OFFSET2_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle OFFSET3_IS_CON_MH = OFFSET3_IS_CON_CS.dynamicInvoker(); + + // Hand-Unrolling compile-constants + private static final CallSite HAND_UNROLLING1_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite HAND_UNROLLING2_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite HAND_UNROLLING3_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final MethodHandle HAND_UNROLLING1_MH = HAND_UNROLLING1_CS.dynamicInvoker(); + private static final MethodHandle HAND_UNROLLING2_MH = HAND_UNROLLING2_CS.dynamicInvoker(); + private static final MethodHandle HAND_UNROLLING3_MH = HAND_UNROLLING3_CS.dynamicInvoker(); + + static void setConstant(CallSite cs, int value) { + MethodHandle constant = MethodHandles.constant(int.class, value); + cs.setTarget(constant); + } + + static void setConstant(CallSite cs, boolean value) { + MethodHandle constant = MethodHandles.constant(boolean.class, value); + cs.setTarget(constant); + } + + static int init_con() { // compile-time constant + try { + return (int) INIT_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean init_is_con() { // compile-time constant + try { + return (boolean) INIT_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int init_con_or_var() { + int init = init_con(); + if (!init_is_con()) { // branch constant folds to true or false + init += ZERO; // LoadI + } + return init; + } + + static int limit_con() { // compile-time constant + try { + return (int) LIMIT_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean limit_is_con() { // compile-time constant + try { + return (boolean) LIMIT_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int limit_con_or_var() { + int limit = limit_con(); + if (!limit_is_con()) { // branch constant folds to true or false + limit -= ZERO; // LoadI + } + return limit; + } + + static int stride_con() { // compile-time constant + try { + return (int) STRIDE_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int scale_con() { // compile-time constant + try { + return (int) SCALE_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset1_con() { // compile-time constant + try { + return (int) OFFSET1_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset2_con() { // compile-time constant + try { + return (int) OFFSET2_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset3_con() { // compile-time constant + try { + return (int) OFFSET3_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean offset1_is_con() { // compile-time constant + try { + return (boolean) OFFSET1_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean offset2_is_con() { // compile-time constant + try { + return (boolean) OFFSET2_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean offset3_is_con() { // compile-time constant + try { + return (boolean) OFFSET3_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset1_con_or_var() { + int offset = offset1_con(); + if (!offset1_is_con()) { // branch constant folds to true or false + offset += ZERO; // LoadI + } + return offset; + } + + static int offset2_con_or_var() { + int offset = offset2_con(); + if (!offset2_is_con()) { // branch constant folds to true or false + offset += ZERO; // LoadI + } + return offset; + } + + static int offset3_con_or_var() { + int offset = offset3_con(); + if (!offset3_is_con()) { // branch constant folds to true or false + offset += ZERO; // LoadI + } + return offset; + } + + static int opposite_direction_offset1_con_or_var() { + // When indexing in the opposite direction to i, we Want to have: + // + // a[x - i * scale] + // + // So we want to fulfill these constraints: + // + // x - init * scale = offset + limit * scale + // x - limit * scale = offset + init * scale + // + // Hence: + // + // x = offset + limit * scale + init * scale; + + int offset = offset1_con_or_var(); + int init = init_con(); + int limit = limit_con(); + int scale = scale_con(); + return offset + limit * scale + init * scale; + } + + static int opposite_direction_offset2_con_or_var() { + int offset = offset2_con_or_var(); + int init = init_con(); + int limit = limit_con(); + int scale = scale_con(); + return offset + limit * scale + init * scale; + } + + static int opposite_direction_offset3_con_or_var() { + int offset = offset3_con_or_var(); + int init = init_con(); + int limit = limit_con(); + int scale = scale_con(); + return offset + limit * scale + init * scale; + } + + static int hand_unrolling1_con() { // compile-time constant + try { + return (int) HAND_UNROLLING1_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int hand_unrolling2_con() { // compile-time constant + try { + return (int) HAND_UNROLLING2_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int hand_unrolling3_con() { // compile-time constant + try { + return (int) HAND_UNROLLING3_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int randomStride() { + return switch (random.nextInt(6)) { + case 0 -> random.nextInt(64) + 1; // [1..64] + case 1, 2, 3 -> 1; + default -> 1 << random.nextInt(7); // powers of 2: 1..64 + }; + } + + static int randomScale() { + return switch (random.nextInt(6)) { + case 0 -> random.nextInt(64) + 1; // [1..64] + case 1, 2, 3 -> 1; + default -> 1 << random.nextInt(7); // powers of 2: 1..64 + }; + } + + static int randomOffsetDiff() { + return switch (random.nextInt(6)) { + case 0 -> random.nextInt(256) + 128; + case 1, 2, 3 -> 0; + case 4 -> +(1 << random.nextInt(8)); // powers of 2: 1..128 + default -> -(1 << random.nextInt(8)); // powers of 2: -1..-128 + }; + } + + static int randomHandUnrolling() { + return switch (random.nextInt(2)) { + case 0 -> random.nextInt(16) + 1; // [1..16] + default -> 1 << random.nextInt(5); // powers of 2: 1..16 + }; + } + + static void setRandomConstants() { + // We want to create random constants for a loop, but they should never go out of bounds. + // We constrain i to be in the range [init..limit], with init < limit. For simplicity, we + // always generate: + // + // 1 <= scale <= 64 + // 1 <= stride <= 64 + // + // We work with this reference memory access: + // + // a[offset + i * scale] + // + // It is up to the test function to re-arrange the the given terms to iterate upward or + // downward, to hand-unroll etc. + // + // We must ensure that the first and last indices are in range: + // + // 0 + error <= offset + init * scale + // offset + limit * scale < range - error + // + // The "error" term is there such that the test functions have the freedom to slightly + // diverge from the reference memory access pattern (for example modify the offset). + // + // The values for scale and range are already fixed. We now want to generate values for + // offset, init and limit. + // + // (1) Fix offset: + // + // init >= (error - offset) / scale + // limit < (range - error - offset) / scale + // + // (2) Fix init: + // + // offset >= error - init * scale + // limit < (range - error - offset) / scale + // + // (3) Fix limit: + // + // offset < range - error - limit * scale + // init >= (error - offset) / scale + // + // We can still slightly perturb the results in the direction permitted by the inequality. + + int stride = randomStride(); + int scale = randomScale(); + int range = RANGE_CON; + int error = 1024; // generous + int init; + int limit; + int offset1; + switch(random.nextInt(3)) { + case 0 -> { + offset1 = random.nextInt(2_000_000) - 1_000_000; + init = (error - offset1) / scale + random.nextInt(64); + limit = (range - error - offset1) / scale - random.nextInt(64); + } + case 1 -> { + init = random.nextInt(2_000_000) - 1_000_000; + offset1 = error - init * scale + random.nextInt(64); + limit = (range - error - offset1) / scale - random.nextInt(64); + } + default -> { + limit = random.nextInt(2_000_000) - 1_000_000; + offset1 = range - error - limit * scale - random.nextInt(64); + init = (error - offset1) / scale + random.nextInt(64); + } + } + + int offset2 = offset1 + randomOffsetDiff(); + int offset3 = offset1 + randomOffsetDiff(); + + // We can toggle the init, limit and offset to either be constant or variable: + boolean init_is_con = random.nextInt(3) != 0; + boolean limit_is_con = random.nextInt(3) != 0; + boolean offset1_is_con = random.nextInt(3) != 0; + boolean offset2_is_con = random.nextInt(3) != 0; + boolean offset3_is_con = random.nextInt(3) != 0; + + int hand_unrolling1 = randomHandUnrolling(); + int hand_unrolling2 = randomHandUnrolling(); + int hand_unrolling3 = randomHandUnrolling(); + +// Overwrite the fuzzed values below to reproduce a specific failure: +// +// init = 1; +// limit = init + 3000; +// offset1 = 0; +// offset2 = 0; +// offset3 = 32 - 2*init; +// stride = 1; +// scale = 2; +// hand_unrolling1 = 0; +// hand_unrolling2 = 0; +// hand_unrolling3 = 4; +// +// init_is_con = true; +// limit_is_con = true; +// offset1_is_con = true; +// offset2_is_con = true; +// offset3_is_con = true; + + System.out.println(" init: " + init + " (con: " + init_is_con + ")"); + System.out.println(" limit: " + limit + " (con: " + limit_is_con + ")"); + System.out.println(" offset1: " + offset1 + " (con: " + offset1_is_con + ")"); + System.out.println(" offset2: " + offset2 + " (con: " + offset2_is_con + ")"); + System.out.println(" offset3: " + offset3 + " (con: " + offset3_is_con + ")"); + System.out.println(" stride: " + stride); + System.out.println(" scale: " + scale); + System.out.println(" hand_unrolling1: " + hand_unrolling1); + System.out.println(" hand_unrolling2: " + hand_unrolling2); + System.out.println(" hand_unrolling3: " + hand_unrolling3); + setConstant(INIT_CS, init); + setConstant(LIMIT_CS, limit); + setConstant(STRIDE_CS, stride); + setConstant(SCALE_CS, scale); + setConstant(OFFSET1_CS, offset1); + setConstant(OFFSET2_CS, offset2); + setConstant(OFFSET3_CS, offset3); + setConstant(INIT_IS_CON_CS, init_is_con); + setConstant(LIMIT_IS_CON_CS, limit_is_con); + setConstant(OFFSET1_IS_CON_CS, offset1_is_con); + setConstant(OFFSET2_IS_CON_CS, offset2_is_con); + setConstant(OFFSET3_IS_CON_CS, offset3_is_con); + setConstant(HAND_UNROLLING1_CS, hand_unrolling1); + setConstant(HAND_UNROLLING2_CS, hand_unrolling2); + setConstant(HAND_UNROLLING3_CS, hand_unrolling3); + } + + public static void main(String[] args) { + byte[] aB = generateB(); + byte[] bB = generateB(); + byte[] cB = generateB(); + short[] aS = generateS(); + short[] bS = generateS(); + short[] cS = generateS(); + char[] aC = generateC(); + char[] bC = generateC(); + char[] cC = generateC(); + int[] aI = generateI(); + int[] bI = generateI(); + int[] cI = generateI(); + long[] aL = generateL(); + long[] bL = generateL(); + long[] cL = generateL(); + float[] aF = generateF(); + float[] bF = generateF(); + float[] cF = generateF(); + double[] aD = generateD(); + double[] bD = generateD(); + double[] cD = generateD(); + + // Add all tests to list + Map tests = new HashMap(); + tests.put("testUUB", () -> { return testUUB(aB.clone()); }); + tests.put("testDDB", () -> { return testDDB(aB.clone()); }); + tests.put("testUDB", () -> { return testUDB(aB.clone()); }); + tests.put("testDUB", () -> { return testDUB(aB.clone()); }); + + tests.put("testUUBH", () -> { return testUUBH(aB.clone()); }); + + tests.put("testUUBBB", () -> { return testUUBBB(aB.clone(), bB.clone(), cB.clone()); }); + tests.put("testUUBSI", () -> { return testUUBSI(aB.clone(), bS.clone(), cI.clone()); }); + + tests.put("testUUBBBH", () -> { return testUUBBBH(aB.clone(), bB.clone(), cB.clone()); }); + + tests.put("testUUBCFH", () -> { return testUUBCFH(aB.clone(), bC.clone(), cF.clone()); }); + tests.put("testDDBCFH", () -> { return testDDBCFH(aB.clone(), bC.clone(), cF.clone()); }); + tests.put("testUDBCFH", () -> { return testUDBCFH(aB.clone(), bC.clone(), cF.clone()); }); + tests.put("testDUBCFH", () -> { return testDUBCFH(aB.clone(), bC.clone(), cF.clone()); }); + + tests.put("testMMSFD", () -> { return testMMSFD(aS.clone(), bF.clone(), cD.clone()); }); + + tests.put("testUU_unsafe_BasI", () -> { return testUU_unsafe_BasI(aB.clone()); }); + tests.put("testUU_unsafe_BasIH", () -> { return testUU_unsafe_BasIH(aB.clone(), bB.clone(), cB.clone()); }); + + + // Only run for 90% of the time, and subtract some margin. This ensures the shutdown has sufficient time, + // even for very slow runs. + long test_time_allowance = System.currentTimeMillis() + + (long)(Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) * 0.9) - + 20_000; + long test_hard_timeout = System.currentTimeMillis() + + Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT); + + for (int i = 1; i <= ITERATIONS_MAX; i++) { + setRandomConstants(); + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + long allowance = test_time_allowance - System.currentTimeMillis(); + long until_timeout = test_hard_timeout - System.currentTimeMillis(); + System.out.println("ITERATION " + i + " of " + ITERATIONS_MAX + ". Test " + name + + ", time allowance: " + allowance + ", until timeout: " + until_timeout); + + // Compute gold value, probably deopt first if constants have changed. + Object[] gold = test.run(); + + // Have enough iterations to (re)compile + for (int j = 0; j < 10_000; j++) { + Object[] result = test.run(); + verify(name, gold, result); + } + + if (System.currentTimeMillis() > test_time_allowance) { + allowance = test_time_allowance - System.currentTimeMillis(); + until_timeout = test_hard_timeout - System.currentTimeMillis(); + System.out.println("TEST PASSED: hit maximal time allownance during iteration " + i + + ", time allowance: " + allowance + ", until timeout: " + until_timeout); + return; + } + } + } + long allowance = test_time_allowance - System.currentTimeMillis(); + long until_timeout = test_hard_timeout - System.currentTimeMillis(); + System.out.println("TEST PASSED, time allowance: " + allowance + ", until timeout: " + until_timeout); + } + + // Test names: + // test + // {U: i goes up, D: i goes down, M: mixed} + // {U: indexing goes up, D: indexing goes down, M: mixed} + // BSCILFD (types used) + + // -------------------- BASIC SINGLE -------------------- + + static Object[] testUUB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset + i * scale]++; + } + return new Object[]{ a }; + } + + static Object[] testDDB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + for (int i = limit; i > init; i -= stride) { + a[offset + i * scale]++; + } + return new Object[]{ a }; + } + + static Object[] testUDB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x = opposite_direction_offset1_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[x - i * scale]++; + } + return new Object[]{ a }; + } + + static Object[] testDUB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x = opposite_direction_offset1_con_or_var(); + + for (int i = limit; i > init; i -= stride) { + a[x - i * scale]++; + } + return new Object[]{ a }; + } + + // -------------------- BASIC HAND UNROLL -------------------- + + static Object[] testUUBH(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + // All if statements with constant h fold to true or false + int h = hand_unrolling1_con(); + + for (int i = init; i < limit; i += stride) { + if (h >= 1) { a[offset + i * scale + 0]++; } + if (h >= 2) { a[offset + i * scale + 1]++; } + if (h >= 3) { a[offset + i * scale + 2]++; } + if (h >= 4) { a[offset + i * scale + 3]++; } + if (h >= 5) { a[offset + i * scale + 4]++; } + if (h >= 6) { a[offset + i * scale + 5]++; } + if (h >= 7) { a[offset + i * scale + 6]++; } + if (h >= 8) { a[offset + i * scale + 7]++; } + if (h >= 9) { a[offset + i * scale + 8]++; } + if (h >= 10) { a[offset + i * scale + 9]++; } + if (h >= 11) { a[offset + i * scale + 10]++; } + if (h >= 12) { a[offset + i * scale + 11]++; } + if (h >= 13) { a[offset + i * scale + 12]++; } + if (h >= 14) { a[offset + i * scale + 13]++; } + if (h >= 15) { a[offset + i * scale + 14]++; } + if (h >= 16) { a[offset + i * scale + 15]++; } + } + return new Object[]{ a }; + } + + // -------------------- BASIC TRIPPLE -------------------- + + static Object[] testUUBBB(byte[] a, byte[] b, byte[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset1 + i * scale]++; + b[offset2 + i * scale]++; + c[offset3 + i * scale]++; + } + return new Object[]{ a, b, c }; + } + + static Object[] testUUBSI(byte[] a, short[] b, int[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset1 + i * scale]++; + b[offset2 + i * scale]++; + c[offset3 + i * scale]++; + } + return new Object[]{ a, b, c }; + } + + // -------------------- HAND UNROLL TRIPPLE -------------------- + + static Object[] testUUBBBH(byte[] a, byte[] b, byte[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testUUBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testDDBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = limit; i > init; i -= stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testUDBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x1 = opposite_direction_offset1_con_or_var(); + int x2 = opposite_direction_offset2_con_or_var(); + int x3 = opposite_direction_offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[x1 - i * scale + 0]++; } + if (h1 >= 2) { a[x1 - i * scale + 1]++; } + if (h1 >= 3) { a[x1 - i * scale + 2]++; } + if (h1 >= 4) { a[x1 - i * scale + 3]++; } + if (h1 >= 5) { a[x1 - i * scale + 4]++; } + if (h1 >= 6) { a[x1 - i * scale + 5]++; } + if (h1 >= 7) { a[x1 - i * scale + 6]++; } + if (h1 >= 8) { a[x1 - i * scale + 7]++; } + if (h1 >= 9) { a[x1 - i * scale + 8]++; } + if (h1 >= 10) { a[x1 - i * scale + 9]++; } + if (h1 >= 11) { a[x1 - i * scale + 10]++; } + if (h1 >= 12) { a[x1 - i * scale + 11]++; } + if (h1 >= 13) { a[x1 - i * scale + 12]++; } + if (h1 >= 14) { a[x1 - i * scale + 13]++; } + if (h1 >= 15) { a[x1 - i * scale + 14]++; } + if (h1 >= 16) { a[x1 - i * scale + 15]++; } + + if (h2 >= 1) { b[x2 - i * scale + 0]++; } + if (h2 >= 2) { b[x2 - i * scale + 1]++; } + if (h2 >= 3) { b[x2 - i * scale + 2]++; } + if (h2 >= 4) { b[x2 - i * scale + 3]++; } + if (h2 >= 5) { b[x2 - i * scale + 4]++; } + if (h2 >= 6) { b[x2 - i * scale + 5]++; } + if (h2 >= 7) { b[x2 - i * scale + 6]++; } + if (h2 >= 8) { b[x2 - i * scale + 7]++; } + if (h2 >= 9) { b[x2 - i * scale + 8]++; } + if (h2 >= 10) { b[x2 - i * scale + 9]++; } + if (h2 >= 11) { b[x2 - i * scale + 10]++; } + if (h2 >= 12) { b[x2 - i * scale + 11]++; } + if (h2 >= 13) { b[x2 - i * scale + 12]++; } + if (h2 >= 14) { b[x2 - i * scale + 13]++; } + if (h2 >= 15) { b[x2 - i * scale + 14]++; } + if (h2 >= 16) { b[x2 - i * scale + 15]++; } + + if (h3 >= 1) { c[x3 - i * scale + 0]++; } + if (h3 >= 2) { c[x3 - i * scale + 1]++; } + if (h3 >= 3) { c[x3 - i * scale + 2]++; } + if (h3 >= 4) { c[x3 - i * scale + 3]++; } + if (h3 >= 5) { c[x3 - i * scale + 4]++; } + if (h3 >= 6) { c[x3 - i * scale + 5]++; } + if (h3 >= 7) { c[x3 - i * scale + 6]++; } + if (h3 >= 8) { c[x3 - i * scale + 7]++; } + if (h3 >= 9) { c[x3 - i * scale + 8]++; } + if (h3 >= 10) { c[x3 - i * scale + 9]++; } + if (h3 >= 11) { c[x3 - i * scale + 10]++; } + if (h3 >= 12) { c[x3 - i * scale + 11]++; } + if (h3 >= 13) { c[x3 - i * scale + 12]++; } + if (h3 >= 14) { c[x3 - i * scale + 13]++; } + if (h3 >= 15) { c[x3 - i * scale + 14]++; } + if (h3 >= 16) { c[x3 - i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testDUBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x1 = opposite_direction_offset1_con_or_var(); + int x2 = opposite_direction_offset2_con_or_var(); + int x3 = opposite_direction_offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = limit; i > init; i -= stride) { + if (h1 >= 1) { a[x1 - i * scale + 0]++; } + if (h1 >= 2) { a[x1 - i * scale + 1]++; } + if (h1 >= 3) { a[x1 - i * scale + 2]++; } + if (h1 >= 4) { a[x1 - i * scale + 3]++; } + if (h1 >= 5) { a[x1 - i * scale + 4]++; } + if (h1 >= 6) { a[x1 - i * scale + 5]++; } + if (h1 >= 7) { a[x1 - i * scale + 6]++; } + if (h1 >= 8) { a[x1 - i * scale + 7]++; } + if (h1 >= 9) { a[x1 - i * scale + 8]++; } + if (h1 >= 10) { a[x1 - i * scale + 9]++; } + if (h1 >= 11) { a[x1 - i * scale + 10]++; } + if (h1 >= 12) { a[x1 - i * scale + 11]++; } + if (h1 >= 13) { a[x1 - i * scale + 12]++; } + if (h1 >= 14) { a[x1 - i * scale + 13]++; } + if (h1 >= 15) { a[x1 - i * scale + 14]++; } + if (h1 >= 16) { a[x1 - i * scale + 15]++; } + + if (h2 >= 1) { b[x2 - i * scale + 0]++; } + if (h2 >= 2) { b[x2 - i * scale + 1]++; } + if (h2 >= 3) { b[x2 - i * scale + 2]++; } + if (h2 >= 4) { b[x2 - i * scale + 3]++; } + if (h2 >= 5) { b[x2 - i * scale + 4]++; } + if (h2 >= 6) { b[x2 - i * scale + 5]++; } + if (h2 >= 7) { b[x2 - i * scale + 6]++; } + if (h2 >= 8) { b[x2 - i * scale + 7]++; } + if (h2 >= 9) { b[x2 - i * scale + 8]++; } + if (h2 >= 10) { b[x2 - i * scale + 9]++; } + if (h2 >= 11) { b[x2 - i * scale + 10]++; } + if (h2 >= 12) { b[x2 - i * scale + 11]++; } + if (h2 >= 13) { b[x2 - i * scale + 12]++; } + if (h2 >= 14) { b[x2 - i * scale + 13]++; } + if (h2 >= 15) { b[x2 - i * scale + 14]++; } + if (h2 >= 16) { b[x2 - i * scale + 15]++; } + + if (h3 >= 1) { c[x3 - i * scale + 0]++; } + if (h3 >= 2) { c[x3 - i * scale + 1]++; } + if (h3 >= 3) { c[x3 - i * scale + 2]++; } + if (h3 >= 4) { c[x3 - i * scale + 3]++; } + if (h3 >= 5) { c[x3 - i * scale + 4]++; } + if (h3 >= 6) { c[x3 - i * scale + 5]++; } + if (h3 >= 7) { c[x3 - i * scale + 6]++; } + if (h3 >= 8) { c[x3 - i * scale + 7]++; } + if (h3 >= 9) { c[x3 - i * scale + 8]++; } + if (h3 >= 10) { c[x3 - i * scale + 9]++; } + if (h3 >= 11) { c[x3 - i * scale + 10]++; } + if (h3 >= 12) { c[x3 - i * scale + 11]++; } + if (h3 >= 13) { c[x3 - i * scale + 12]++; } + if (h3 >= 14) { c[x3 - i * scale + 13]++; } + if (h3 >= 15) { c[x3 - i * scale + 14]++; } + if (h3 >= 16) { c[x3 - i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + // -------------------- MIXED DIRECTION TRIPPLE -------------------- + + static Object[] testMMSFD(short[] a, float[] b, double[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = opposite_direction_offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset1 + i * scale]++; + b[offset2 - i * scale]++; + c[offset3 + i * scale]++; + } + return new Object[]{ a, b, c }; + } + + // -------------------- UNSAFE -------------------- + + static Object[] testUU_unsafe_BasI(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + for (int i = init; i < limit; i += stride) { + int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale; + int v = UNSAFE.getIntUnaligned(a, adr); + UNSAFE.putIntUnaligned(a, adr, v + 1); + } + return new Object[]{ a }; + } + + static Object[] testUU_unsafe_BasIH(byte[] a, byte[] b, byte[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + int adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale; + int adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale; + int adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale; + + if (h1 >= 1) { UNSAFE.putIntUnaligned(a, adr1 + 0*4, UNSAFE.getIntUnaligned(a, adr1 + 0*4) + 1); } + if (h1 >= 2) { UNSAFE.putIntUnaligned(a, adr1 + 1*4, UNSAFE.getIntUnaligned(a, adr1 + 1*4) + 1); } + if (h1 >= 3) { UNSAFE.putIntUnaligned(a, adr1 + 2*4, UNSAFE.getIntUnaligned(a, adr1 + 2*4) + 1); } + if (h1 >= 4) { UNSAFE.putIntUnaligned(a, adr1 + 3*4, UNSAFE.getIntUnaligned(a, adr1 + 3*4) + 1); } + if (h1 >= 5) { UNSAFE.putIntUnaligned(a, adr1 + 4*4, UNSAFE.getIntUnaligned(a, adr1 + 4*4) + 1); } + if (h1 >= 6) { UNSAFE.putIntUnaligned(a, adr1 + 5*4, UNSAFE.getIntUnaligned(a, adr1 + 5*4) + 1); } + if (h1 >= 7) { UNSAFE.putIntUnaligned(a, adr1 + 6*4, UNSAFE.getIntUnaligned(a, adr1 + 6*4) + 1); } + if (h1 >= 8) { UNSAFE.putIntUnaligned(a, adr1 + 7*4, UNSAFE.getIntUnaligned(a, adr1 + 7*4) + 1); } + if (h1 >= 9) { UNSAFE.putIntUnaligned(a, adr1 + 8*4, UNSAFE.getIntUnaligned(a, adr1 + 8*4) + 1); } + if (h1 >= 10) { UNSAFE.putIntUnaligned(a, adr1 + 9*4, UNSAFE.getIntUnaligned(a, adr1 + 9*4) + 1); } + if (h1 >= 11) { UNSAFE.putIntUnaligned(a, adr1 + 10*4, UNSAFE.getIntUnaligned(a, adr1 + 10*4) + 1); } + if (h1 >= 12) { UNSAFE.putIntUnaligned(a, adr1 + 11*4, UNSAFE.getIntUnaligned(a, adr1 + 11*4) + 1); } + if (h1 >= 13) { UNSAFE.putIntUnaligned(a, adr1 + 12*4, UNSAFE.getIntUnaligned(a, adr1 + 12*4) + 1); } + if (h1 >= 14) { UNSAFE.putIntUnaligned(a, adr1 + 13*4, UNSAFE.getIntUnaligned(a, adr1 + 13*4) + 1); } + if (h1 >= 15) { UNSAFE.putIntUnaligned(a, adr1 + 14*4, UNSAFE.getIntUnaligned(a, adr1 + 14*4) + 1); } + if (h1 >= 16) { UNSAFE.putIntUnaligned(a, adr1 + 15*4, UNSAFE.getIntUnaligned(a, adr1 + 15*4) + 1); } + + if (h2 >= 1) { UNSAFE.putIntUnaligned(b, adr2 + 0*4, UNSAFE.getIntUnaligned(b, adr2 + 0*4) + 1); } + if (h2 >= 2) { UNSAFE.putIntUnaligned(b, adr2 + 1*4, UNSAFE.getIntUnaligned(b, adr2 + 1*4) + 1); } + if (h2 >= 3) { UNSAFE.putIntUnaligned(b, adr2 + 2*4, UNSAFE.getIntUnaligned(b, adr2 + 2*4) + 1); } + if (h2 >= 4) { UNSAFE.putIntUnaligned(b, adr2 + 3*4, UNSAFE.getIntUnaligned(b, adr2 + 3*4) + 1); } + if (h2 >= 5) { UNSAFE.putIntUnaligned(b, adr2 + 4*4, UNSAFE.getIntUnaligned(b, adr2 + 4*4) + 1); } + if (h2 >= 6) { UNSAFE.putIntUnaligned(b, adr2 + 5*4, UNSAFE.getIntUnaligned(b, adr2 + 5*4) + 1); } + if (h2 >= 7) { UNSAFE.putIntUnaligned(b, adr2 + 6*4, UNSAFE.getIntUnaligned(b, adr2 + 6*4) + 1); } + if (h2 >= 8) { UNSAFE.putIntUnaligned(b, adr2 + 7*4, UNSAFE.getIntUnaligned(b, adr2 + 7*4) + 1); } + if (h2 >= 9) { UNSAFE.putIntUnaligned(b, adr2 + 8*4, UNSAFE.getIntUnaligned(b, adr2 + 8*4) + 1); } + if (h2 >= 10) { UNSAFE.putIntUnaligned(b, adr2 + 9*4, UNSAFE.getIntUnaligned(b, adr2 + 9*4) + 1); } + if (h2 >= 11) { UNSAFE.putIntUnaligned(b, adr2 + 10*4, UNSAFE.getIntUnaligned(b, adr2 + 10*4) + 1); } + if (h2 >= 12) { UNSAFE.putIntUnaligned(b, adr2 + 11*4, UNSAFE.getIntUnaligned(b, adr2 + 11*4) + 1); } + if (h2 >= 13) { UNSAFE.putIntUnaligned(b, adr2 + 12*4, UNSAFE.getIntUnaligned(b, adr2 + 12*4) + 1); } + if (h2 >= 14) { UNSAFE.putIntUnaligned(b, adr2 + 13*4, UNSAFE.getIntUnaligned(b, adr2 + 13*4) + 1); } + if (h2 >= 15) { UNSAFE.putIntUnaligned(b, adr2 + 14*4, UNSAFE.getIntUnaligned(b, adr2 + 14*4) + 1); } + if (h2 >= 16) { UNSAFE.putIntUnaligned(b, adr2 + 15*4, UNSAFE.getIntUnaligned(b, adr2 + 15*4) + 1); } + + if (h3 >= 1) { UNSAFE.putIntUnaligned(c, adr3 + 0*4, UNSAFE.getIntUnaligned(c, adr3 + 0*4) + 1); } + if (h3 >= 2) { UNSAFE.putIntUnaligned(c, adr3 + 1*4, UNSAFE.getIntUnaligned(c, adr3 + 1*4) + 1); } + if (h3 >= 3) { UNSAFE.putIntUnaligned(c, adr3 + 2*4, UNSAFE.getIntUnaligned(c, adr3 + 2*4) + 1); } + if (h3 >= 4) { UNSAFE.putIntUnaligned(c, adr3 + 3*4, UNSAFE.getIntUnaligned(c, adr3 + 3*4) + 1); } + if (h3 >= 5) { UNSAFE.putIntUnaligned(c, adr3 + 4*4, UNSAFE.getIntUnaligned(c, adr3 + 4*4) + 1); } + if (h3 >= 6) { UNSAFE.putIntUnaligned(c, adr3 + 5*4, UNSAFE.getIntUnaligned(c, adr3 + 5*4) + 1); } + if (h3 >= 7) { UNSAFE.putIntUnaligned(c, adr3 + 6*4, UNSAFE.getIntUnaligned(c, adr3 + 6*4) + 1); } + if (h3 >= 8) { UNSAFE.putIntUnaligned(c, adr3 + 7*4, UNSAFE.getIntUnaligned(c, adr3 + 7*4) + 1); } + if (h3 >= 9) { UNSAFE.putIntUnaligned(c, adr3 + 8*4, UNSAFE.getIntUnaligned(c, adr3 + 8*4) + 1); } + if (h3 >= 10) { UNSAFE.putIntUnaligned(c, adr3 + 9*4, UNSAFE.getIntUnaligned(c, adr3 + 9*4) + 1); } + if (h3 >= 11) { UNSAFE.putIntUnaligned(c, adr3 + 10*4, UNSAFE.getIntUnaligned(c, adr3 + 10*4) + 1); } + if (h3 >= 12) { UNSAFE.putIntUnaligned(c, adr3 + 11*4, UNSAFE.getIntUnaligned(c, adr3 + 11*4) + 1); } + if (h3 >= 13) { UNSAFE.putIntUnaligned(c, adr3 + 12*4, UNSAFE.getIntUnaligned(c, adr3 + 12*4) + 1); } + if (h3 >= 14) { UNSAFE.putIntUnaligned(c, adr3 + 13*4, UNSAFE.getIntUnaligned(c, adr3 + 13*4) + 1); } + if (h3 >= 15) { UNSAFE.putIntUnaligned(c, adr3 + 14*4, UNSAFE.getIntUnaligned(c, adr3 + 14*4) + 1); } + if (h3 >= 16) { UNSAFE.putIntUnaligned(c, adr3 + 15*4, UNSAFE.getIntUnaligned(c, adr3 + 15*4) + 1); } + } + return new Object[]{ a, b, c }; + } + + static byte[] generateB() { + byte[] a = new byte[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (byte)random.nextInt(); + } + return a; + } + + static char[] generateC() { + char[] a = new char[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (char)random.nextInt(); + } + return a; + } + + static short[] generateS() { + short[] a = new short[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (short)random.nextInt(); + } + return a; + } + + static int[] generateI() { + int[] a = new int[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = random.nextInt(); + } + return a; + } + + static long[] generateL() { + long[] a = new long[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = random.nextLong(); + } + return a; + } + + static float[] generateF() { + float[] a = new float[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = Float.intBitsToFloat(random.nextInt()); + } + return a; + } + + static double[] generateD() { + double[] a = new double[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = Double.longBitsToDouble(random.nextLong()); + } + return a; + } + + static void verify(String name, Object[] gold, Object[] result) { + if (gold.length != result.length) { + throw new RuntimeException("verify " + name + ": not the same number of outputs: gold.length = " + + gold.length + ", result.length = " + result.length); + } + for (int i = 0; i < gold.length; i++) { + Object g = gold[i]; + Object r = result[i]; + if (g.getClass() != r.getClass() || !g.getClass().isArray() || !r.getClass().isArray()) { + throw new RuntimeException("verify " + name + ": must both be array of same type:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + if (g == r) { + throw new RuntimeException("verify " + name + ": should be two separate arrays (with identical content):" + + " gold[" + i + "] == result[" + i + "]"); + } + if (Array.getLength(g) != Array.getLength(r)) { + throw new RuntimeException("verify " + name + ": arrays must have same length:" + + " gold[" + i + "].length = " + Array.getLength(g) + + " result[" + i + "].length = " + Array.getLength(r)); + } + Class c = g.getClass().getComponentType(); + if (c == byte.class) { + verifyB(name, i, (byte[])g, (byte[])r); + } else if (c == char.class) { + verifyC(name, i, (char[])g, (char[])r); + } else if (c == short.class) { + verifyS(name, i, (short[])g, (short[])r); + } else if (c == int.class) { + verifyI(name, i, (int[])g, (int[])r); + } else if (c == long.class) { + verifyL(name, i, (long[])g, (long[])r); + } else if (c == float.class) { + verifyF(name, i, (float[])g, (float[])r); + } else if (c == double.class) { + verifyD(name, i, (double[])g, (double[])r); + } else { + throw new RuntimeException("verify " + name + ": array type not supported for verify:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + } + } + + static void verifyB(String name, int i, byte[] g, byte[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyB " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyC(String name, int i, char[] g, char[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyC " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyS(String name, int i, short[] g, short[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyS " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyI(String name, int i, int[] g, int[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyI " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyL(String name, int i, long[] g, long[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyL " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyF(String name, int i, float[] g, float[] r) { + for (int j = 0; j < g.length; j++) { + int gv = UNSAFE.getInt(g, UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4 * j); + int rv = UNSAFE.getInt(r, UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4 * j); + if (gv != rv) { + throw new RuntimeException("verifyF " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + gv + + " result[" + i + "][" + j + "] = " + rv); + } + } + } + + static void verifyD(String name, int i, double[] g, double[] r) { + for (int j = 0; j < g.length; j++) { + long gv = UNSAFE.getLong(g, UNSAFE.ARRAY_DOUBLE_BASE_OFFSET + 8 * j); + long rv = UNSAFE.getLong(r, UNSAFE.ARRAY_DOUBLE_BASE_OFFSET + 8 * j); + if (gv != rv) { + throw new RuntimeException("verifyF " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + gv + + " result[" + i + "][" + j + "] = " + rv); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index 105b07b8758..1e48ae07106 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, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * and various MaxVectorSize values, and +- AlignVector. * * Note: this test is auto-generated. Please modify / generate with script: - * https://bugs.openjdk.org/browse/JDK-8312570 + * https://bugs.openjdk.org/browse/JDK-8310190 * * Types: int, long, short, char, byte, float, double * Offsets: 0, -1, 1, -2, 2, -3, 3, -4, 4, -7, 7, -8, 8, -14, 14, -16, 16, -18, 18, -20, 20, -31, 31, -32, 32, -63, 63, -64, 64, -65, 65, -128, 128, -129, 129, -192, 192 @@ -49,8 +49,7 @@ * Note: sizeofop(type) = sizeof(type), except sizeofop(char) = 2 * * Different types can lead to different vector_width. This depends on - * the CPU-features. Thus, we have a positive and negative IR rule per - * CPU-feature for each test. + * the CPU-features. * * Definition: * MaxVectorSize: limit through flag @@ -66,31 +65,53 @@ * or some additional optimization collapses some Loads, and suddenly cyclic * dependency disappears, and we can vectorize. * - * With '-XX:+AlignVector', we would like to check that we vectorize exactly iff: - * byte_offset % actual_vector_width == 0 - * Because all vector_widths are powers of 2, this is equivalent to: - * pow2_factor(byte_offset) >= actual_vector_width - * where pow2_factor computes the largest power of 2 that is a factor of the number. + * With '-XX:+AlignVector' we do the following: * - * Under these assumptions, we know there must be vectorization: - * pow2_factor(byte_offset) >= vector_width + * Must vectorize cleanly if: + * 1) guaranteed no misalignment AND + * 2) guaratneed no cyclic dependency + * + * Must not vectorize at all if: + * 1) guaranteed misalignment AND + * 2) guaranteed no cyclic dependency + * + * We could imagine a case with cyclic dependency, where C2 detects + * that only the first load is needed, and so no vectorization is + * required for it, and hence the store vector can be aligned. + * + * The alignment criteria is + * byte_offset % aw == 0 + * where align width (aw) is + * aw = min(actual_vector_width, ObjectAlignmentInBytes) + * For simplicity, we assume that ObjectAlignmentInBytes == 8, + * which currently can only be changed manually and then no IR + * rule is run. + * This allows us to do the computation statically. + * Further, we define: + * aw_min = min(min_vector_width, ObjectAlignmentInBytes) + * aw_max = min(vector_width, ObjectAlignmentInBytes) + * aw_min <= aw <= aw_max + * + * Again, we have no cyclic dependency, except when: + * byte_offset > 0 and p.vector_width > byte_offset + * Here we must ensure that: + * byte_offset >= MaxVectorSize + * + * Guaranteed no misalignment: + * byte_offset % aw_max == 0 * implies - * pow2_factor(byte_offset) >= actual_vector_width - * MaxVectorSize >= min_vector_size - * else any vectorization is impossible. + * byte_offset % aw == 0 * - * And under the following conditions no vectorization is possible: - * byte_offset < 0: No cyclic dependency. - * Cyclic dependency could lead to Load removals, then only the store is vectorized. - * byte_offset % min_vector_width != 0 + * Guaranteed misalignment: + * byte_offset % aw_min != 0 * implies - * byte_offset % actual_vector_width != 0 + * byte_offset % aw != 0 * */ /* * @test id=vanilla-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @library /test/lib / @@ -99,7 +120,7 @@ /* * @test id=vanilla-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @library /test/lib / @@ -108,7 +129,7 @@ /* * @test id=sse4-v016-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -119,7 +140,7 @@ /* * @test id=sse4-v016-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -130,7 +151,7 @@ /* * @test id=sse4-v008-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -141,7 +162,7 @@ /* * @test id=sse4-v008-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -152,7 +173,7 @@ /* * @test id=sse4-v004-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -163,7 +184,7 @@ /* * @test id=sse4-v004-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -174,7 +195,7 @@ /* * @test id=sse4-v002-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -185,7 +206,7 @@ /* * @test id=sse4-v002-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -196,7 +217,7 @@ /* * @test id=avx1-v032-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -207,7 +228,7 @@ /* * @test id=avx1-v032-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -218,7 +239,7 @@ /* * @test id=avx1-v016-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -229,7 +250,7 @@ /* * @test id=avx1-v016-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -240,7 +261,7 @@ /* * @test id=avx2-v032-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -251,7 +272,7 @@ /* * @test id=avx2-v032-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -262,7 +283,7 @@ /* * @test id=avx2-v016-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -273,7 +294,7 @@ /* * @test id=avx2-v016-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -284,7 +305,7 @@ /* * @test id=avx512-v064-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -295,7 +316,7 @@ /* * @test id=avx512-v064-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -306,7 +327,7 @@ /* * @test id=avx512-v032-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -317,7 +338,7 @@ /* * @test id=avx512-v032-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -328,7 +349,7 @@ /* * @test id=avx512bw-v064-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -339,7 +360,7 @@ /* * @test id=avx512bw-v064-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -350,7 +371,7 @@ /* * @test id=avx512bw-v032-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -361,7 +382,7 @@ /* * @test id=avx512bw-v032-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -372,7 +393,7 @@ /* * @test id=vec-v064-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -382,7 +403,7 @@ /* * @test id=vec-v064-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -392,7 +413,7 @@ /* * @test id=vec-v032-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -402,7 +423,7 @@ /* * @test id=vec-v032-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -412,7 +433,7 @@ /* * @test id=vec-v016-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -422,7 +443,7 @@ /* * @test id=vec-v016-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -432,7 +453,7 @@ /* * @test id=vec-v008-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -442,7 +463,7 @@ /* * @test id=vec-v008-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -452,7 +473,7 @@ /* * @test id=vec-v004-A - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -462,7 +483,7 @@ /* * @test id=vec-v004-U - * @bug 8298935 8308606 8310308 8312570 + * @bug 8298935 8308606 8310308 8312570 8310190 * @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") @@ -1392,22 +1413,42 @@ public static void main(String args[]) { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP0(int[] data) { for (int j = 0; j < RANGE; j++) { data[j + 0] = (int)(data[j] * (int)-11); @@ -1428,7 +1469,7 @@ public static void runIntP0() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -1436,7 +1477,7 @@ public static void runIntP0() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -1444,7 +1485,7 @@ public static void runIntP0() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -1452,7 +1493,7 @@ public static void runIntP0() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -1460,7 +1501,7 @@ public static void runIntP0() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -1483,18 +1524,38 @@ public static void runIntM1() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP1(int[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (int)(data[j] * (int)-11); @@ -1515,22 +1576,42 @@ public static void runIntP1() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM2(int[] data) { for (int j = 2; j < RANGE; j++) { data[j + -2] = (int)(data[j] * (int)-11); @@ -1550,27 +1631,47 @@ public static void runIntM2() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeature = {"sve", "true"}) public static void testIntP2(int[] data) { for (int j = 0; j < RANGE - 2; j++) { @@ -1592,7 +1693,7 @@ public static void runIntP2() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -1600,7 +1701,7 @@ public static void runIntP2() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -1608,7 +1709,7 @@ public static void runIntP2() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -1616,7 +1717,7 @@ public static void runIntP2() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -1624,7 +1725,7 @@ public static void runIntP2() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -1649,26 +1750,46 @@ public static void runIntM3() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP3(int[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (int)(data[j] * (int)-11); @@ -1689,22 +1810,42 @@ public static void runIntP3() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM4(int[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (int)(data[j] * (int)-11); @@ -1725,7 +1866,7 @@ public static void runIntM4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -1734,16 +1875,24 @@ public static void runIntM4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -1752,6 +1901,10 @@ public static void runIntM4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP4(int[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (int)(data[j] * (int)-11); @@ -1772,7 +1925,7 @@ public static void runIntP4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -1780,7 +1933,7 @@ public static void runIntP4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -1788,7 +1941,7 @@ public static void runIntP4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -1796,7 +1949,7 @@ public static void runIntP4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -1804,7 +1957,7 @@ public static void runIntP4() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -1828,25 +1981,45 @@ public static void runIntM7() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP7(int[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (int)(data[j] * (int)-11); @@ -1867,22 +2040,42 @@ public static void runIntP7() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM8(int[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (int)(data[j] * (int)-11); @@ -1903,7 +2096,7 @@ public static void runIntM8() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -1911,7 +2104,7 @@ public static void runIntM8() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -1920,11 +2113,15 @@ public static void runIntM8() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -1933,6 +2130,10 @@ public static void runIntM8() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP8(int[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (int)(data[j] * (int)-11); @@ -1953,22 +2154,42 @@ public static void runIntP8() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM14(int[] data) { for (int j = 14; j < RANGE; j++) { data[j + -14] = (int)(data[j] * (int)-11); @@ -1989,24 +2210,44 @@ public static void runIntM14() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP14(int[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (int)(data[j] * (int)-11); @@ -2027,22 +2268,42 @@ public static void runIntP14() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM16(int[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (int)(data[j] * (int)-11); @@ -2063,7 +2324,7 @@ public static void runIntM16() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2071,7 +2332,7 @@ public static void runIntM16() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2079,7 +2340,7 @@ public static void runIntM16() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2087,7 +2348,7 @@ public static void runIntM16() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2096,6 +2357,10 @@ public static void runIntM16() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP16(int[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (int)(data[j] * (int)-11); @@ -2116,22 +2381,42 @@ public static void runIntP16() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM18(int[] data) { for (int j = 18; j < RANGE; j++) { data[j + -18] = (int)(data[j] * (int)-11); @@ -2152,23 +2437,43 @@ public static void runIntM18() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 72 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP18(int[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (int)(data[j] * (int)-11); @@ -2189,22 +2494,42 @@ public static void runIntP18() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM20(int[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (int)(data[j] * (int)-11); @@ -2225,7 +2550,7 @@ public static void runIntM20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2233,15 +2558,23 @@ public static void runIntM20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2250,6 +2583,10 @@ public static void runIntM20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP20(int[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (int)(data[j] * (int)-11); @@ -2270,7 +2607,7 @@ public static void runIntP20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2278,7 +2615,7 @@ public static void runIntP20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2286,7 +2623,7 @@ public static void runIntP20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2294,7 +2631,7 @@ public static void runIntP20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2302,7 +2639,7 @@ public static void runIntP20() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -2326,23 +2663,43 @@ public static void runIntM31() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 124 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 124"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 124"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP31(int[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (int)(data[j] * (int)-11); @@ -2363,22 +2720,42 @@ public static void runIntP31() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM32(int[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (int)(data[j] * (int)-11); @@ -2399,7 +2776,7 @@ public static void runIntM32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2407,7 +2784,7 @@ public static void runIntM32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2415,7 +2792,7 @@ public static void runIntM32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2423,7 +2800,7 @@ public static void runIntM32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2432,6 +2809,10 @@ public static void runIntM32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP32(int[] data) { for (int j = 0; j < RANGE - 32; j++) { data[j + 32] = (int)(data[j] * (int)-11); @@ -2452,7 +2833,7 @@ public static void runIntP32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2460,7 +2841,7 @@ public static void runIntP32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2468,7 +2849,7 @@ public static void runIntP32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2476,7 +2857,7 @@ public static void runIntP32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2484,7 +2865,7 @@ public static void runIntP32() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -2508,23 +2889,43 @@ public static void runIntM63() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 - // positive byte_offset 252 can lead to cyclic dependency + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 + // positive byte_offset 252 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 252"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 252"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP63(int[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (int)(data[j] * (int)-11); @@ -2545,22 +2946,42 @@ public static void runIntP63() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM64(int[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (int)(data[j] * (int)-11); @@ -2581,7 +3002,7 @@ public static void runIntM64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2589,7 +3010,7 @@ public static void runIntM64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2597,7 +3018,7 @@ public static void runIntM64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2605,7 +3026,7 @@ public static void runIntM64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2613,7 +3034,7 @@ public static void runIntM64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) @@ -2637,7 +3058,7 @@ public static void runIntP64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2645,7 +3066,7 @@ public static void runIntP64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2653,7 +3074,7 @@ public static void runIntP64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2661,7 +3082,7 @@ public static void runIntP64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2669,7 +3090,7 @@ public static void runIntP64() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -2693,22 +3114,42 @@ public static void runIntM65() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP65(int[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (int)(data[j] * (int)-11); @@ -2729,22 +3170,42 @@ public static void runIntP65() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM128(int[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (int)(data[j] * (int)-11); @@ -2765,7 +3226,7 @@ public static void runIntM128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2773,7 +3234,7 @@ public static void runIntM128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2781,7 +3242,7 @@ public static void runIntM128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2789,7 +3250,7 @@ public static void runIntM128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2797,7 +3258,7 @@ public static void runIntM128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) @@ -2821,7 +3282,7 @@ public static void runIntP128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2829,7 +3290,7 @@ public static void runIntP128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2837,7 +3298,7 @@ public static void runIntP128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2845,7 +3306,7 @@ public static void runIntP128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2853,7 +3314,7 @@ public static void runIntP128() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -2877,22 +3338,42 @@ public static void runIntM129() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_I, IRNode.MUL_VI, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntP129(int[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (int)(data[j] * (int)-11); @@ -2913,22 +3394,42 @@ public static void runIntP129() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testIntM192(int[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (int)(data[j] * (int)-11); @@ -2949,7 +3450,7 @@ public static void runIntM192() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -2957,7 +3458,7 @@ public static void runIntM192() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -2965,7 +3466,7 @@ public static void runIntM192() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -2973,7 +3474,7 @@ public static void runIntM192() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -2981,7 +3482,7 @@ public static void runIntM192() { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) @@ -3005,22 +3506,42 @@ public static void runIntP192() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP0(long[] data) { for (int j = 0; j < RANGE; j++) { data[j + 0] = (long)(data[j] + (long)-11); @@ -3041,41 +3562,41 @@ public static void runLongP0() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM1(long[] data) { for (int j = 1; j < RANGE; j++) { @@ -3096,18 +3617,28 @@ public static void runLongM1() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 2 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: asimd -> vector_width: 16 -> elements in vector: 2 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. public static void testLongP1(long[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (long)(data[j] + (long)-11); @@ -3128,22 +3659,42 @@ public static void runLongP1() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM2(long[] data) { for (int j = 2; j < RANGE; j++) { data[j + -2] = (long)(data[j] + (long)-11); @@ -3164,32 +3715,44 @@ public static void runLongM2() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 16"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 16"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, + applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 16"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, + applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongP2(long[] data) { for (int j = 0; j < RANGE - 2; j++) { @@ -3211,41 +3774,41 @@ public static void runLongP2() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM3(long[] data) { for (int j = 3; j < RANGE; j++) { @@ -3267,25 +3830,45 @@ public static void runLongM3() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 // positive byte_offset 24 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 24 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 24 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP3(long[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (long)(data[j] + (long)-11); @@ -3306,22 +3889,42 @@ public static void runLongP3() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM4(long[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (long)(data[j] + (long)-11); @@ -3342,7 +3945,7 @@ public static void runLongM4() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -3350,7 +3953,7 @@ public static void runLongM4() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -3359,11 +3962,15 @@ public static void runLongM4() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -3372,6 +3979,10 @@ public static void runLongM4() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP4(long[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (long)(data[j] + (long)-11); @@ -3392,41 +4003,41 @@ public static void runLongP4() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM7(long[] data) { for (int j = 7; j < RANGE; j++) { @@ -3448,24 +4059,44 @@ public static void runLongM7() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP7(long[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (long)(data[j] + (long)-11); @@ -3486,22 +4117,42 @@ public static void runLongP7() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM8(long[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (long)(data[j] + (long)-11); @@ -3522,7 +4173,7 @@ public static void runLongM8() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -3530,7 +4181,7 @@ public static void runLongM8() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -3538,7 +4189,7 @@ public static void runLongM8() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -3546,7 +4197,7 @@ public static void runLongM8() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -3555,6 +4206,10 @@ public static void runLongM8() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP8(long[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (long)(data[j] + (long)-11); @@ -3575,22 +4230,42 @@ public static void runLongP8() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM14(long[] data) { for (int j = 14; j < RANGE; j++) { data[j + -14] = (long)(data[j] + (long)-11); @@ -3611,7 +4286,7 @@ public static void runLongM14() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -3619,15 +4294,23 @@ public static void runLongM14() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -3636,6 +4319,10 @@ public static void runLongM14() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP14(long[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (long)(data[j] + (long)-11); @@ -3656,22 +4343,42 @@ public static void runLongP14() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM16(long[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (long)(data[j] + (long)-11); @@ -3692,7 +4399,7 @@ public static void runLongM16() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -3700,7 +4407,7 @@ public static void runLongM16() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -3708,7 +4415,7 @@ public static void runLongM16() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -3716,7 +4423,7 @@ public static void runLongM16() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -3725,6 +4432,10 @@ public static void runLongM16() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP16(long[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (long)(data[j] + (long)-11); @@ -3745,22 +4456,42 @@ public static void runLongP16() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM18(long[] data) { for (int j = 18; j < RANGE; j++) { data[j + -18] = (long)(data[j] + (long)-11); @@ -3781,7 +4512,7 @@ public static void runLongM18() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -3789,15 +4520,23 @@ public static void runLongM18() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -3806,6 +4545,10 @@ public static void runLongM18() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP18(long[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (long)(data[j] + (long)-11); @@ -3826,22 +4569,42 @@ public static void runLongP18() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM20(long[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (long)(data[j] + (long)-11); @@ -3862,7 +4625,7 @@ public static void runLongM20() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -3870,7 +4633,7 @@ public static void runLongM20() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -3878,11 +4641,15 @@ public static void runLongM20() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -3891,6 +4658,10 @@ public static void runLongM20() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP20(long[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (long)(data[j] + (long)-11); @@ -3911,41 +4682,41 @@ public static void runLongP20() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM31(long[] data) { for (int j = 31; j < RANGE; j++) { @@ -3967,23 +4738,43 @@ public static void runLongM31() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 248 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP31(long[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (long)(data[j] + (long)-11); @@ -4004,22 +4795,42 @@ public static void runLongP31() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM32(long[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (long)(data[j] + (long)-11); @@ -4040,7 +4851,7 @@ public static void runLongM32() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -4048,7 +4859,7 @@ public static void runLongM32() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -4056,7 +4867,7 @@ public static void runLongM32() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -4064,7 +4875,7 @@ public static void runLongM32() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -4072,7 +4883,7 @@ public static void runLongM32() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -4096,41 +4907,41 @@ public static void runLongP32() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM63(long[] data) { for (int j = 63; j < RANGE; j++) { @@ -4152,22 +4963,42 @@ public static void runLongM63() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP63(long[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (long)(data[j] + (long)-11); @@ -4188,22 +5019,42 @@ public static void runLongP63() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM64(long[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (long)(data[j] + (long)-11); @@ -4224,7 +5075,7 @@ public static void runLongM64() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -4232,7 +5083,7 @@ public static void runLongM64() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -4240,7 +5091,7 @@ public static void runLongM64() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -4248,7 +5099,7 @@ public static void runLongM64() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -4256,7 +5107,7 @@ public static void runLongM64() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -4280,41 +5131,41 @@ public static void runLongP64() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM65(long[] data) { for (int j = 65; j < RANGE; j++) { @@ -4336,22 +5187,42 @@ public static void runLongM65() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP65(long[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (long)(data[j] + (long)-11); @@ -4372,22 +5243,42 @@ public static void runLongP65() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM128(long[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (long)(data[j] + (long)-11); @@ -4408,7 +5299,7 @@ public static void runLongM128() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -4416,7 +5307,7 @@ public static void runLongM128() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -4424,7 +5315,7 @@ public static void runLongM128() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -4432,7 +5323,7 @@ public static void runLongM128() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -4440,7 +5331,7 @@ public static void runLongM128() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -4464,41 +5355,41 @@ public static void runLongP128() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_L, IRNode.ADD_VL, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testLongM129(long[] data) { for (int j = 129; j < RANGE; j++) { @@ -4520,22 +5411,42 @@ public static void runLongM129() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongP129(long[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (long)(data[j] + (long)-11); @@ -4556,22 +5467,42 @@ public static void runLongP129() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testLongM192(long[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (long)(data[j] + (long)-11); @@ -4592,7 +5523,7 @@ public static void runLongM192() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -4600,7 +5531,7 @@ public static void runLongM192() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512", "false"}) @@ -4608,7 +5539,7 @@ public static void runLongM192() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -4616,7 +5547,7 @@ public static void runLongM192() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -4624,7 +5555,7 @@ public static void runLongM192() { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_VL, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -4648,22 +5579,42 @@ public static void runLongP192() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP0(short[] data) { for (int j = 0; j < RANGE; j++) { data[j + 0] = (short)(data[j] * (short)-11); @@ -4684,7 +5635,7 @@ public static void runShortP0() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -4692,7 +5643,7 @@ public static void runShortP0() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -4700,7 +5651,7 @@ public static void runShortP0() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -4708,7 +5659,7 @@ public static void runShortP0() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -4716,7 +5667,7 @@ public static void runShortP0() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -4739,18 +5690,38 @@ public static void runShortM1() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP1(short[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (short)(data[j] * (short)-11); @@ -4771,22 +5742,27 @@ public static void runShortP1() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testShortM2(short[] data) { for (int j = 2; j < RANGE; j++) { data[j + -2] = (short)(data[j] * (short)-11); @@ -4806,28 +5782,33 @@ public static void runShortM2() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testShortP2(short[] data) { for (int j = 0; j < RANGE - 2; j++) { data[j + 2] = (short)(data[j] * (short)-11); @@ -4848,7 +5829,7 @@ public static void runShortP2() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -4856,7 +5837,7 @@ public static void runShortP2() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -4864,7 +5845,7 @@ public static void runShortP2() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -4872,7 +5853,7 @@ public static void runShortP2() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -4880,7 +5861,7 @@ public static void runShortP2() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -4905,26 +5886,46 @@ public static void runShortM3() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP3(short[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (short)(data[j] * (short)-11); @@ -4945,22 +5946,42 @@ public static void runShortP3() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM4(short[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (short)(data[j] * (short)-11); @@ -4982,26 +6003,46 @@ public static void runShortM4() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP4(short[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (short)(data[j] * (short)-11); @@ -5022,7 +6063,7 @@ public static void runShortP4() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5030,7 +6071,7 @@ public static void runShortP4() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5038,7 +6079,7 @@ public static void runShortP4() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -5046,7 +6087,7 @@ public static void runShortP4() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5054,7 +6095,7 @@ public static void runShortP4() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -5079,26 +6120,46 @@ public static void runShortM7() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP7(short[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (short)(data[j] * (short)-11); @@ -5119,22 +6180,42 @@ public static void runShortP7() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM8(short[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (short)(data[j] * (short)-11); @@ -5155,7 +6236,7 @@ public static void runShortM8() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5164,16 +6245,24 @@ public static void runShortM8() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5182,6 +6271,10 @@ public static void runShortM8() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP8(short[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (short)(data[j] * (short)-11); @@ -5202,22 +6295,27 @@ public static void runShortP8() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testShortM14(short[] data) { for (int j = 14; j < RANGE; j++) { data[j + -14] = (short)(data[j] * (short)-11); @@ -5238,25 +6336,30 @@ public static void runShortM14() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testShortP14(short[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (short)(data[j] * (short)-11); @@ -5277,22 +6380,42 @@ public static void runShortP14() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM16(short[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (short)(data[j] * (short)-11); @@ -5313,7 +6436,7 @@ public static void runShortM16() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5321,7 +6444,7 @@ public static void runShortM16() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5330,11 +6453,15 @@ public static void runShortM16() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5343,6 +6470,10 @@ public static void runShortM16() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP16(short[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (short)(data[j] * (short)-11); @@ -5363,22 +6494,27 @@ public static void runShortP16() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testShortM18(short[] data) { for (int j = 18; j < RANGE; j++) { data[j + -18] = (short)(data[j] * (short)-11); @@ -5399,24 +6535,29 @@ public static void runShortM18() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 36 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 36 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testShortP18(short[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (short)(data[j] * (short)-11); @@ -5437,22 +6578,42 @@ public static void runShortP18() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM20(short[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (short)(data[j] * (short)-11); @@ -5473,24 +6634,44 @@ public static void runShortM20() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 40 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 40 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP20(short[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (short)(data[j] * (short)-11); @@ -5511,7 +6692,7 @@ public static void runShortP20() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5519,7 +6700,7 @@ public static void runShortP20() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5527,7 +6708,7 @@ public static void runShortP20() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -5535,7 +6716,7 @@ public static void runShortP20() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5543,7 +6724,7 @@ public static void runShortP20() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -5567,24 +6748,44 @@ public static void runShortM31() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 62 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 62 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP31(short[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (short)(data[j] * (short)-11); @@ -5605,22 +6806,42 @@ public static void runShortP31() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM32(short[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (short)(data[j] * (short)-11); @@ -5641,7 +6862,7 @@ public static void runShortM32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5649,7 +6870,7 @@ public static void runShortM32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5657,7 +6878,7 @@ public static void runShortM32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -5665,7 +6886,7 @@ public static void runShortM32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5674,6 +6895,10 @@ public static void runShortM32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP32(short[] data) { for (int j = 0; j < RANGE - 32; j++) { data[j + 32] = (short)(data[j] * (short)-11); @@ -5694,7 +6919,7 @@ public static void runShortP32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5702,7 +6927,7 @@ public static void runShortP32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5710,7 +6935,7 @@ public static void runShortP32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -5718,7 +6943,7 @@ public static void runShortP32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5726,7 +6951,7 @@ public static void runShortP32() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -5750,23 +6975,43 @@ public static void runShortM63() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 126 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 126"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 126"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP63(short[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (short)(data[j] * (short)-11); @@ -5787,22 +7032,42 @@ public static void runShortP63() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM64(short[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (short)(data[j] * (short)-11); @@ -5823,7 +7088,7 @@ public static void runShortM64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5831,7 +7096,7 @@ public static void runShortM64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5839,7 +7104,7 @@ public static void runShortM64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -5847,7 +7112,7 @@ public static void runShortM64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5856,6 +7121,10 @@ public static void runShortM64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP64(short[] data) { for (int j = 0; j < RANGE - 64; j++) { data[j + 64] = (short)(data[j] * (short)-11); @@ -5876,7 +7145,7 @@ public static void runShortP64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -5884,7 +7153,7 @@ public static void runShortP64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -5892,7 +7161,7 @@ public static void runShortP64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -5900,7 +7169,7 @@ public static void runShortP64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -5908,7 +7177,7 @@ public static void runShortP64() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -5932,23 +7201,43 @@ public static void runShortM65() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 130 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 130"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 130"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP65(short[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (short)(data[j] * (short)-11); @@ -5969,22 +7258,42 @@ public static void runShortP65() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM128(short[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (short)(data[j] * (short)-11); @@ -6005,7 +7314,7 @@ public static void runShortM128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6013,7 +7322,7 @@ public static void runShortM128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6021,7 +7330,7 @@ public static void runShortM128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -6029,7 +7338,7 @@ public static void runShortM128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6037,7 +7346,7 @@ public static void runShortM128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) @@ -6061,7 +7370,7 @@ public static void runShortP128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6069,7 +7378,7 @@ public static void runShortP128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6077,7 +7386,7 @@ public static void runShortP128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -6085,7 +7394,7 @@ public static void runShortP128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6093,7 +7402,7 @@ public static void runShortP128() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -6117,22 +7426,42 @@ public static void runShortM129() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_S, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP129(short[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (short)(data[j] * (short)-11); @@ -6153,22 +7482,42 @@ public static void runShortP129() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortM192(short[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (short)(data[j] * (short)-11); @@ -6189,7 +7538,7 @@ public static void runShortM192() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6197,7 +7546,7 @@ public static void runShortM192() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6205,7 +7554,7 @@ public static void runShortM192() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -6213,7 +7562,7 @@ public static void runShortM192() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6221,6 +7570,10 @@ public static void runShortM192() { @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testShortP192(short[] data) { for (int j = 0; j < RANGE - 192; j++) { data[j + 192] = (short)(data[j] * (short)-11); @@ -6241,24 +7594,44 @@ public static void runShortP192() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - public static void testCharP0(char[] data) { - for (int j = 0; j < RANGE; j++) { + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) + public static void testCharP0(char[] data) { + for (int j = 0; j < RANGE; j++) { data[j + 0] = (char)(data[j] * (char)-11); } } @@ -6277,7 +7650,7 @@ public static void runCharP0() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6285,7 +7658,7 @@ public static void runCharP0() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6293,7 +7666,7 @@ public static void runCharP0() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -6301,7 +7674,7 @@ public static void runCharP0() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6309,7 +7682,7 @@ public static void runCharP0() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -6332,18 +7705,38 @@ public static void runCharM1() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP1(char[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (char)(data[j] * (char)-11); @@ -6364,22 +7757,27 @@ public static void runCharP1() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testCharM2(char[] data) { for (int j = 2; j < RANGE; j++) { data[j + -2] = (char)(data[j] * (char)-11); @@ -6399,28 +7797,33 @@ public static void runCharM2() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testCharP2(char[] data) { for (int j = 0; j < RANGE - 2; j++) { data[j + 2] = (char)(data[j] * (char)-11); @@ -6441,7 +7844,7 @@ public static void runCharP2() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6449,7 +7852,7 @@ public static void runCharP2() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6457,7 +7860,7 @@ public static void runCharP2() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -6465,7 +7868,7 @@ public static void runCharP2() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6473,7 +7876,7 @@ public static void runCharP2() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -6498,26 +7901,46 @@ public static void runCharM3() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 6 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 6"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 6"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP3(char[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (char)(data[j] * (char)-11); @@ -6538,22 +7961,42 @@ public static void runCharP3() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM4(char[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (char)(data[j] * (char)-11); @@ -6575,26 +8018,46 @@ public static void runCharM4() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP4(char[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (char)(data[j] * (char)-11); @@ -6615,7 +8078,7 @@ public static void runCharP4() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6623,7 +8086,7 @@ public static void runCharP4() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6631,7 +8094,7 @@ public static void runCharP4() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -6639,7 +8102,7 @@ public static void runCharP4() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6647,7 +8110,7 @@ public static void runCharP4() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -6672,26 +8135,46 @@ public static void runCharM7() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP7(char[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (char)(data[j] * (char)-11); @@ -6712,22 +8195,42 @@ public static void runCharP7() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM8(char[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (char)(data[j] * (char)-11); @@ -6748,7 +8251,7 @@ public static void runCharM8() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6757,16 +8260,24 @@ public static void runCharM8() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6775,6 +8286,10 @@ public static void runCharM8() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP8(char[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (char)(data[j] * (char)-11); @@ -6795,22 +8310,27 @@ public static void runCharP8() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testCharM14(char[] data) { for (int j = 14; j < RANGE; j++) { data[j + -14] = (char)(data[j] * (char)-11); @@ -6831,25 +8351,30 @@ public static void runCharM14() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testCharP14(char[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (char)(data[j] * (char)-11); @@ -6870,22 +8395,42 @@ public static void runCharP14() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM16(char[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (char)(data[j] * (char)-11); @@ -6906,7 +8451,7 @@ public static void runCharM16() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -6914,7 +8459,7 @@ public static void runCharM16() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -6923,11 +8468,15 @@ public static void runCharM16() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -6936,6 +8485,10 @@ public static void runCharM16() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP16(char[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (char)(data[j] * (char)-11); @@ -6956,22 +8509,27 @@ public static void runCharP16() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testCharM18(char[] data) { for (int j = 18; j < RANGE; j++) { data[j + -18] = (char)(data[j] * (char)-11); @@ -6992,24 +8550,29 @@ public static void runCharM18() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 36 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 36 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 36"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testCharP18(char[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (char)(data[j] * (char)-11); @@ -7030,22 +8593,42 @@ public static void runCharP18() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM20(char[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (char)(data[j] * (char)-11); @@ -7066,24 +8649,44 @@ public static void runCharM20() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 40 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 40 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 40"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP20(char[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (char)(data[j] * (char)-11); @@ -7104,7 +8707,7 @@ public static void runCharP20() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7112,7 +8715,7 @@ public static void runCharP20() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7120,7 +8723,7 @@ public static void runCharP20() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7128,7 +8731,7 @@ public static void runCharP20() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7136,7 +8739,7 @@ public static void runCharP20() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -7160,24 +8763,44 @@ public static void runCharM31() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 // positive byte_offset 62 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 62 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 62"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 62"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP31(char[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (char)(data[j] * (char)-11); @@ -7198,22 +8821,42 @@ public static void runCharP31() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM32(char[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (char)(data[j] * (char)-11); @@ -7234,7 +8877,7 @@ public static void runCharM32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7242,7 +8885,7 @@ public static void runCharM32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7250,7 +8893,7 @@ public static void runCharM32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7258,7 +8901,7 @@ public static void runCharM32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7267,6 +8910,10 @@ public static void runCharM32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP32(char[] data) { for (int j = 0; j < RANGE - 32; j++) { data[j + 32] = (char)(data[j] * (char)-11); @@ -7287,7 +8934,7 @@ public static void runCharP32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7295,7 +8942,7 @@ public static void runCharP32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7303,7 +8950,7 @@ public static void runCharP32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7311,7 +8958,7 @@ public static void runCharP32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7319,7 +8966,7 @@ public static void runCharP32() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -7343,23 +8990,43 @@ public static void runCharM63() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 126 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 126"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 126"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP63(char[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (char)(data[j] * (char)-11); @@ -7380,22 +9047,42 @@ public static void runCharP63() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM64(char[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (char)(data[j] * (char)-11); @@ -7416,7 +9103,7 @@ public static void runCharM64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7424,7 +9111,7 @@ public static void runCharM64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7432,7 +9119,7 @@ public static void runCharM64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7440,7 +9127,7 @@ public static void runCharM64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7449,6 +9136,10 @@ public static void runCharM64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP64(char[] data) { for (int j = 0; j < RANGE - 64; j++) { data[j + 64] = (char)(data[j] * (char)-11); @@ -7469,7 +9160,7 @@ public static void runCharP64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7477,7 +9168,7 @@ public static void runCharP64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7485,7 +9176,7 @@ public static void runCharP64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7493,7 +9184,7 @@ public static void runCharP64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7501,7 +9192,7 @@ public static void runCharP64() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -7525,23 +9216,43 @@ public static void runCharM65() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 // positive byte_offset 130 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 130"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 130"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP65(char[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (char)(data[j] * (char)-11); @@ -7562,22 +9273,42 @@ public static void runCharP65() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM128(char[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (char)(data[j] * (char)-11); @@ -7598,7 +9329,7 @@ public static void runCharM128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7606,7 +9337,7 @@ public static void runCharM128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7614,7 +9345,7 @@ public static void runCharM128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7622,7 +9353,7 @@ public static void runCharM128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7630,7 +9361,7 @@ public static void runCharM128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) @@ -7654,7 +9385,7 @@ public static void runCharP128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7662,7 +9393,7 @@ public static void runCharP128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7670,7 +9401,7 @@ public static void runCharP128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7678,7 +9409,7 @@ public static void runCharP128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7686,7 +9417,7 @@ public static void runCharP128() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -7710,22 +9441,42 @@ public static void runCharM129() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_C, IRNode.MUL_VS, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP129(char[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (char)(data[j] * (char)-11); @@ -7746,22 +9497,42 @@ public static void runCharP129() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 128 @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharM192(char[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (char)(data[j] * (char)-11); @@ -7782,7 +9553,7 @@ public static void runCharM192() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7790,7 +9561,7 @@ public static void runCharM192() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7798,7 +9569,7 @@ public static void runCharM192() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7806,7 +9577,7 @@ public static void runCharM192() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7814,6 +9585,10 @@ public static void runCharM192() { @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_C, "> 0", IRNode.MUL_VS, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testCharP192(char[] data) { for (int j = 0; j < RANGE - 192; j++) { data[j + 192] = (char)(data[j] * (char)-11); @@ -7834,22 +9609,42 @@ public static void runCharP192() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP0(byte[] data) { for (int j = 0; j < RANGE; j++) { data[j + 0] = (byte)(data[j] * (byte)11); @@ -7870,7 +9665,7 @@ public static void runByteP0() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7878,7 +9673,7 @@ public static void runByteP0() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7886,7 +9681,7 @@ public static void runByteP0() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7894,7 +9689,7 @@ public static void runByteP0() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7902,7 +9697,7 @@ public static void runByteP0() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -7925,18 +9720,38 @@ public static void runByteM1() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 1 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 1 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 1 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 1 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 1 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 1"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP1(byte[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (byte)(data[j] * (byte)11); @@ -7957,7 +9772,7 @@ public static void runByteP1() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -7965,7 +9780,7 @@ public static void runByteP1() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -7973,7 +9788,7 @@ public static void runByteP1() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -7981,7 +9796,7 @@ public static void runByteP1() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -7989,7 +9804,7 @@ public static void runByteP1() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8012,18 +9827,38 @@ public static void runByteM2() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 2 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 2"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP2(byte[] data) { for (int j = 0; j < RANGE - 2; j++) { data[j + 2] = (byte)(data[j] * (byte)11); @@ -8044,7 +9879,7 @@ public static void runByteP2() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8052,7 +9887,7 @@ public static void runByteP2() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8060,7 +9895,7 @@ public static void runByteP2() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -8068,7 +9903,7 @@ public static void runByteP2() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8076,7 +9911,7 @@ public static void runByteP2() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8099,18 +9934,38 @@ public static void runByteM3() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 3 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 3 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 3 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 3 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 3 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 3"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP3(byte[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (byte)(data[j] * (byte)11); @@ -8131,22 +9986,27 @@ public static void runByteP3() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testByteM4(byte[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (byte)(data[j] * (byte)11); @@ -8166,28 +10026,33 @@ public static void runByteM4() { // CPU: sse4.1 to avx -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 4 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 4"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testByteP4(byte[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (byte)(data[j] * (byte)11); @@ -8208,7 +10073,7 @@ public static void runByteP4() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8216,7 +10081,7 @@ public static void runByteP4() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8224,7 +10089,7 @@ public static void runByteP4() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -8232,7 +10097,7 @@ public static void runByteP4() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8240,7 +10105,7 @@ public static void runByteP4() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8265,26 +10130,46 @@ public static void runByteM7() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 7 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 7 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 7 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 7 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 7"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 7"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP7(byte[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (byte)(data[j] * (byte)11); @@ -8305,22 +10190,42 @@ public static void runByteP7() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteM8(byte[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (byte)(data[j] * (byte)11); @@ -8342,26 +10247,46 @@ public static void runByteM8() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP8(byte[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (byte)(data[j] * (byte)11); @@ -8382,7 +10307,7 @@ public static void runByteP8() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8390,7 +10315,7 @@ public static void runByteP8() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8398,7 +10323,7 @@ public static void runByteP8() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -8406,7 +10331,7 @@ public static void runByteP8() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8414,7 +10339,7 @@ public static void runByteP8() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8439,26 +10364,46 @@ public static void runByteM14() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 14 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 14"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 14"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP14(byte[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (byte)(data[j] * (byte)11); @@ -8479,22 +10424,42 @@ public static void runByteP14() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteM16(byte[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (byte)(data[j] * (byte)11); @@ -8515,7 +10480,7 @@ public static void runByteM16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8524,16 +10489,24 @@ public static void runByteM16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8542,6 +10515,10 @@ public static void runByteM16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP16(byte[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (byte)(data[j] * (byte)11); @@ -8562,7 +10539,7 @@ public static void runByteP16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8570,7 +10547,7 @@ public static void runByteP16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8578,7 +10555,7 @@ public static void runByteP16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -8586,7 +10563,7 @@ public static void runByteP16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8594,7 +10571,7 @@ public static void runByteP16() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8618,25 +10595,45 @@ public static void runByteM18() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 18 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 18"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 18"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 18 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 18"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 18"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 18 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 18"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 18"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP18(byte[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (byte)(data[j] * (byte)11); @@ -8657,22 +10654,27 @@ public static void runByteP18() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testByteM20(byte[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (byte)(data[j] * (byte)11); @@ -8693,25 +10695,30 @@ public static void runByteM20() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 20 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 20"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 20 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 20"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 20 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 20"}, applyIfCPUFeature = {"sve", "true"}) + // Alignment unclear -> no IR rule for -XX:+AlignVector. public static void testByteP20(byte[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (byte)(data[j] * (byte)11); @@ -8732,7 +10739,7 @@ public static void runByteP20() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8740,7 +10747,7 @@ public static void runByteP20() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8748,7 +10755,7 @@ public static void runByteP20() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -8756,7 +10763,7 @@ public static void runByteP20() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8764,7 +10771,7 @@ public static void runByteP20() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8788,25 +10795,45 @@ public static void runByteM31() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 // positive byte_offset 31 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 31"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 31"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 31 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 31"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 31"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 31 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 31"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 31"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP31(byte[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (byte)(data[j] * (byte)11); @@ -8827,22 +10854,42 @@ public static void runByteP31() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteM32(byte[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (byte)(data[j] * (byte)11); @@ -8863,7 +10910,7 @@ public static void runByteM32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8871,7 +10918,7 @@ public static void runByteM32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8880,11 +10927,15 @@ public static void runByteM32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8893,6 +10944,10 @@ public static void runByteM32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP32(byte[] data) { for (int j = 0; j < RANGE - 32; j++) { data[j + 32] = (byte)(data[j] * (byte)11); @@ -8913,7 +10968,7 @@ public static void runByteP32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -8921,7 +10976,7 @@ public static void runByteP32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -8929,7 +10984,7 @@ public static void runByteP32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -8937,7 +10992,7 @@ public static void runByteP32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -8945,7 +11000,7 @@ public static void runByteP32() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -8969,24 +11024,44 @@ public static void runByteM63() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 // positive byte_offset 63 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 63"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 63"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 63 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 63"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 63"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP63(byte[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (byte)(data[j] * (byte)11); @@ -9007,22 +11082,42 @@ public static void runByteP63() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteM64(byte[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (byte)(data[j] * (byte)11); @@ -9043,7 +11138,7 @@ public static void runByteM64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -9051,7 +11146,7 @@ public static void runByteM64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -9059,7 +11154,7 @@ public static void runByteM64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -9067,7 +11162,7 @@ public static void runByteM64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9076,6 +11171,10 @@ public static void runByteM64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP64(byte[] data) { for (int j = 0; j < RANGE - 64; j++) { data[j + 64] = (byte)(data[j] * (byte)11); @@ -9096,7 +11195,7 @@ public static void runByteP64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -9104,7 +11203,7 @@ public static void runByteP64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -9112,7 +11211,7 @@ public static void runByteP64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -9120,7 +11219,7 @@ public static void runByteP64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9128,7 +11227,7 @@ public static void runByteP64() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -9152,23 +11251,43 @@ public static void runByteM65() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 65 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 65"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 65"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP65(byte[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (byte)(data[j] * (byte)11); @@ -9189,22 +11308,42 @@ public static void runByteP65() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteM128(byte[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (byte)(data[j] * (byte)11); @@ -9225,7 +11364,7 @@ public static void runByteM128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -9233,7 +11372,7 @@ public static void runByteM128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -9241,7 +11380,7 @@ public static void runByteM128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -9249,7 +11388,7 @@ public static void runByteM128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9258,6 +11397,10 @@ public static void runByteM128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP128(byte[] data) { for (int j = 0; j < RANGE - 128; j++) { data[j + 128] = (byte)(data[j] * (byte)11); @@ -9278,7 +11421,7 @@ public static void runByteP128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -9286,7 +11429,7 @@ public static void runByteP128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -9294,7 +11437,7 @@ public static void runByteP128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -9302,7 +11445,7 @@ public static void runByteP128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9310,7 +11453,7 @@ public static void runByteP128() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -9334,23 +11477,43 @@ public static void runByteM129() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 // positive byte_offset 129 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 129"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_B, IRNode.MUL_VB, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 129"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP129(byte[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (byte)(data[j] * (byte)11); @@ -9371,22 +11534,42 @@ public static void runByteP129() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) // CPU: avx2 to avx512 without avx512bw -> vector_width: 32 -> elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) // CPU: avx512bw -> vector_width: 64 -> elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"avx512bw", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 256 @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteM192(byte[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (byte)(data[j] * (byte)11); @@ -9407,7 +11590,7 @@ public static void runByteM192() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "false"}) @@ -9415,7 +11598,7 @@ public static void runByteM192() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx512bw", "false"}) @@ -9423,7 +11606,7 @@ public static void runByteM192() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeature = {"avx512bw", "true"}) @@ -9431,7 +11614,7 @@ public static void runByteM192() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9440,6 +11623,10 @@ public static void runByteM192() { @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 192"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", IRNode.MUL_VB, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 4", "MaxVectorSize", "<= 192"}, + applyIfCPUFeature = {"sve", "true"}) public static void testByteP192(byte[] data) { for (int j = 0; j < RANGE - 192; j++) { data[j + 192] = (byte)(data[j] * (byte)11); @@ -9460,21 +11647,41 @@ public static void runByteP192() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) public static void testFloatP0(float[] data) { for (int j = 0; j < RANGE; j++) { @@ -9496,7 +11703,7 @@ public static void runFloatP0() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -9504,7 +11711,7 @@ public static void runFloatP0() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -9512,7 +11719,7 @@ public static void runFloatP0() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -9520,7 +11727,7 @@ public static void runFloatP0() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9528,7 +11735,7 @@ public static void runFloatP0() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -9551,18 +11758,38 @@ public static void runFloatM1() { // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 4 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 4"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP1(float[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (float)(data[j] * (float)1.001f); @@ -9583,22 +11810,42 @@ public static void runFloatP1() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM2(float[] data) { for (int j = 2; j < RANGE; j++) { data[j + -2] = (float)(data[j] * (float)1.001f); @@ -9618,27 +11865,47 @@ public static void runFloatM2() { // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 8 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 8"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "8"}, + applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "8"}, applyIfCPUFeature = {"sve", "true"}) public static void testFloatP2(float[] data) { for (int j = 0; j < RANGE - 2; j++) { @@ -9660,7 +11927,7 @@ public static void runFloatP2() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -9668,7 +11935,7 @@ public static void runFloatP2() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -9676,7 +11943,7 @@ public static void runFloatP2() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -9684,7 +11951,7 @@ public static void runFloatP2() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9692,7 +11959,7 @@ public static void runFloatP2() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -9717,26 +11984,46 @@ public static void runFloatM3() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 12 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 12"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 12"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP3(float[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (float)(data[j] * (float)1.001f); @@ -9757,22 +12044,42 @@ public static void runFloatP3() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM4(float[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (float)(data[j] * (float)1.001f); @@ -9793,7 +12100,7 @@ public static void runFloatM4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -9802,16 +12109,24 @@ public static void runFloatM4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9820,6 +12135,10 @@ public static void runFloatM4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP4(float[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (float)(data[j] * (float)1.001f); @@ -9840,7 +12159,7 @@ public static void runFloatP4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -9848,7 +12167,7 @@ public static void runFloatP4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -9856,7 +12175,7 @@ public static void runFloatP4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -9864,7 +12183,7 @@ public static void runFloatP4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -9872,7 +12191,7 @@ public static void runFloatP4() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -9896,25 +12215,45 @@ public static void runFloatM7() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 28 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 28"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 28"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP7(float[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (float)(data[j] * (float)1.001f); @@ -9935,22 +12274,42 @@ public static void runFloatP7() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM8(float[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (float)(data[j] * (float)1.001f); @@ -9971,7 +12330,7 @@ public static void runFloatM8() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -9979,7 +12338,7 @@ public static void runFloatM8() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -9988,11 +12347,15 @@ public static void runFloatM8() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10001,6 +12364,10 @@ public static void runFloatM8() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP8(float[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (float)(data[j] * (float)1.001f); @@ -10021,22 +12388,42 @@ public static void runFloatP8() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM14(float[] data) { for (int j = 14; j < RANGE; j++) { data[j + -14] = (float)(data[j] * (float)1.001f); @@ -10057,24 +12444,44 @@ public static void runFloatM14() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP14(float[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (float)(data[j] * (float)1.001f); @@ -10095,22 +12502,42 @@ public static void runFloatP14() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM16(float[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (float)(data[j] * (float)1.001f); @@ -10131,7 +12558,7 @@ public static void runFloatM16() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10139,7 +12566,7 @@ public static void runFloatM16() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10147,7 +12574,7 @@ public static void runFloatM16() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10155,7 +12582,7 @@ public static void runFloatM16() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10164,6 +12591,10 @@ public static void runFloatM16() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP16(float[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (float)(data[j] * (float)1.001f); @@ -10184,22 +12615,42 @@ public static void runFloatP16() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM18(float[] data) { for (int j = 18; j < RANGE; j++) { data[j + -18] = (float)(data[j] * (float)1.001f); @@ -10220,23 +12671,43 @@ public static void runFloatM18() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 72 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 72"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP18(float[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (float)(data[j] * (float)1.001f); @@ -10257,22 +12728,42 @@ public static void runFloatP18() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM20(float[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (float)(data[j] * (float)1.001f); @@ -10293,7 +12784,7 @@ public static void runFloatM20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10301,15 +12792,23 @@ public static void runFloatM20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10318,6 +12817,10 @@ public static void runFloatM20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 80"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP20(float[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (float)(data[j] * (float)1.001f); @@ -10338,7 +12841,7 @@ public static void runFloatP20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10346,7 +12849,7 @@ public static void runFloatP20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10354,7 +12857,7 @@ public static void runFloatP20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10362,7 +12865,7 @@ public static void runFloatP20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10370,7 +12873,7 @@ public static void runFloatP20() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -10394,23 +12897,43 @@ public static void runFloatM31() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 124 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 124"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 124"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP31(float[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (float)(data[j] * (float)1.001f); @@ -10431,22 +12954,42 @@ public static void runFloatP31() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM32(float[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (float)(data[j] * (float)1.001f); @@ -10467,7 +13010,7 @@ public static void runFloatM32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10475,7 +13018,7 @@ public static void runFloatM32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10483,7 +13026,7 @@ public static void runFloatM32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10491,7 +13034,7 @@ public static void runFloatM32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10500,6 +13043,10 @@ public static void runFloatM32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP32(float[] data) { for (int j = 0; j < RANGE - 32; j++) { data[j + 32] = (float)(data[j] * (float)1.001f); @@ -10520,7 +13067,7 @@ public static void runFloatP32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10528,7 +13075,7 @@ public static void runFloatP32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10536,7 +13083,7 @@ public static void runFloatP32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10544,7 +13091,7 @@ public static void runFloatP32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10552,7 +13099,7 @@ public static void runFloatP32() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -10576,23 +13123,43 @@ public static void runFloatM63() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 // positive byte_offset 252 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8", "MaxVectorSize", "<= 252"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "<= 252"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP63(float[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (float)(data[j] * (float)1.001f); @@ -10613,22 +13180,42 @@ public static void runFloatP63() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM64(float[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (float)(data[j] * (float)1.001f); @@ -10649,7 +13236,7 @@ public static void runFloatM64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10657,7 +13244,7 @@ public static void runFloatM64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10665,7 +13252,7 @@ public static void runFloatM64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10673,7 +13260,7 @@ public static void runFloatM64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10681,7 +13268,7 @@ public static void runFloatM64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) @@ -10705,7 +13292,7 @@ public static void runFloatP64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10713,7 +13300,7 @@ public static void runFloatP64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10721,7 +13308,7 @@ public static void runFloatP64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10729,7 +13316,7 @@ public static void runFloatP64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10737,7 +13324,7 @@ public static void runFloatP64() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -10761,22 +13348,42 @@ public static void runFloatM65() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP65(float[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (float)(data[j] * (float)1.001f); @@ -10797,22 +13404,42 @@ public static void runFloatP65() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM128(float[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (float)(data[j] * (float)1.001f); @@ -10833,7 +13460,7 @@ public static void runFloatM128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10841,7 +13468,7 @@ public static void runFloatM128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10849,7 +13476,7 @@ public static void runFloatM128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10857,7 +13484,7 @@ public static void runFloatM128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10865,7 +13492,7 @@ public static void runFloatM128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) @@ -10889,7 +13516,7 @@ public static void runFloatP128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -10897,7 +13524,7 @@ public static void runFloatP128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -10905,7 +13532,7 @@ public static void runFloatP128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"avx512", "true"}) @@ -10913,7 +13540,7 @@ public static void runFloatP128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -10921,7 +13548,7 @@ public static void runFloatP128() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. + // Expect misalignment. @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, applyIf = {"AlignVector", "true"}, applyIfCPUFeature = {"sve", "true"}) @@ -10945,22 +13572,42 @@ public static void runFloatM129() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect misalignment. + @IR(failOn = {IRNode.LOAD_VECTOR_F, IRNode.MUL_VF, IRNode.STORE_VECTOR}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatP129(float[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (float)(data[j] * (float)1.001f); @@ -10981,22 +13628,42 @@ public static void runFloatP129() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 16 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 64 @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, + applyIfCPUFeature = {"sve", "true"}) public static void testFloatM192(float[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (float)(data[j] * (float)1.001f); @@ -11017,7 +13684,7 @@ public static void runFloatM192() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11025,7 +13692,7 @@ public static void runFloatM192() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -11033,7 +13700,7 @@ public static void runFloatM192() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"avx512", "true"}) @@ -11041,7 +13708,7 @@ public static void runFloatM192() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11049,7 +13716,7 @@ public static void runFloatM192() { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_VF, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 8"}, applyIfCPUFeature = {"sve", "true"}) @@ -11073,22 +13740,42 @@ public static void runFloatP192() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP0(double[] data) { for (int j = 0; j < RANGE; j++) { data[j + 0] = (double)(data[j] * (double)1.001); @@ -11109,41 +13796,41 @@ public static void runDoubleP0() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM1(double[] data) { for (int j = 1; j < RANGE; j++) { @@ -11164,18 +13851,28 @@ public static void runDoubleM1() { // CPU: sse4.1 -> vector_width: 16 -> elements in vector: 2 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: asimd -> vector_width: 16 -> elements in vector: 2 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 8 can lead to cyclic dependency // No positive IR rule: conditions impossible. + // Expect alignment. + // No positive IR rule: conditions impossible. public static void testDoubleP1(double[] data) { for (int j = 0; j < RANGE - 1; j++) { data[j + 1] = (double)(data[j] * (double)1.001); @@ -11196,22 +13893,42 @@ public static void runDoubleP1() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM2(double[] data) { for (int j = 2; j < RANGE; j++) { data[j + -2] = (double)(data[j] * (double)1.001); @@ -11232,32 +13949,44 @@ public static void runDoubleM2() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 16"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 16"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, + applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 16 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 16"}, + applyIfAnd = {"AlignVector", "false", "MaxVectorSize", "16"}, + applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", "16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP2(double[] data) { for (int j = 0; j < RANGE - 2; j++) { @@ -11279,41 +14008,41 @@ public static void runDoubleP2() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM3(double[] data) { for (int j = 3; j < RANGE; j++) { @@ -11335,25 +14064,45 @@ public static void runDoubleM3() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 // positive byte_offset 24 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 24 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 24 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 24"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP3(double[] data) { for (int j = 0; j < RANGE - 3; j++) { data[j + 3] = (double)(data[j] * (double)1.001); @@ -11374,22 +14123,42 @@ public static void runDoubleP3() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM4(double[] data) { for (int j = 4; j < RANGE; j++) { data[j + -4] = (double)(data[j] * (double)1.001); @@ -11410,7 +14179,7 @@ public static void runDoubleM4() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11418,7 +14187,7 @@ public static void runDoubleM4() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -11427,11 +14196,15 @@ public static void runDoubleM4() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11440,6 +14213,10 @@ public static void runDoubleM4() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 32"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP4(double[] data) { for (int j = 0; j < RANGE - 4; j++) { data[j + 4] = (double)(data[j] * (double)1.001); @@ -11460,41 +14237,41 @@ public static void runDoubleP4() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM7(double[] data) { for (int j = 7; j < RANGE; j++) { @@ -11516,24 +14293,44 @@ public static void runDoubleM7() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 56 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 56"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP7(double[] data) { for (int j = 0; j < RANGE - 7; j++) { data[j + 7] = (double)(data[j] * (double)1.001); @@ -11554,22 +14351,42 @@ public static void runDoubleP7() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM8(double[] data) { for (int j = 8; j < RANGE; j++) { data[j + -8] = (double)(data[j] * (double)1.001); @@ -11590,7 +14407,7 @@ public static void runDoubleM8() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11598,7 +14415,7 @@ public static void runDoubleM8() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -11606,7 +14423,7 @@ public static void runDoubleM8() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -11614,7 +14431,7 @@ public static void runDoubleM8() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11623,6 +14440,10 @@ public static void runDoubleM8() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 64"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP8(double[] data) { for (int j = 0; j < RANGE - 8; j++) { data[j + 8] = (double)(data[j] * (double)1.001); @@ -11643,22 +14464,42 @@ public static void runDoubleP8() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM14(double[] data) { for (int j = 14; j < RANGE; j++) { data[j + -14] = (double)(data[j] * (double)1.001); @@ -11679,7 +14520,7 @@ public static void runDoubleM14() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11687,15 +14528,23 @@ public static void runDoubleM14() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11704,6 +14553,10 @@ public static void runDoubleM14() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 112"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP14(double[] data) { for (int j = 0; j < RANGE - 14; j++) { data[j + 14] = (double)(data[j] * (double)1.001); @@ -11724,22 +14577,42 @@ public static void runDoubleP14() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM16(double[] data) { for (int j = 16; j < RANGE; j++) { data[j + -16] = (double)(data[j] * (double)1.001); @@ -11760,7 +14633,7 @@ public static void runDoubleM16() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11768,7 +14641,7 @@ public static void runDoubleM16() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -11776,7 +14649,7 @@ public static void runDoubleM16() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -11784,7 +14657,7 @@ public static void runDoubleM16() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11793,6 +14666,10 @@ public static void runDoubleM16() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 128"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP16(double[] data) { for (int j = 0; j < RANGE - 16; j++) { data[j + 16] = (double)(data[j] * (double)1.001); @@ -11813,22 +14690,42 @@ public static void runDoubleP16() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM18(double[] data) { for (int j = 18; j < RANGE; j++) { data[j + -18] = (double)(data[j] * (double)1.001); @@ -11849,7 +14746,7 @@ public static void runDoubleM18() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11857,15 +14754,23 @@ public static void runDoubleM18() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11874,6 +14779,10 @@ public static void runDoubleM18() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 144"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP18(double[] data) { for (int j = 0; j < RANGE - 18; j++) { data[j + 18] = (double)(data[j] * (double)1.001); @@ -11894,22 +14803,42 @@ public static void runDoubleP18() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM20(double[] data) { for (int j = 20; j < RANGE; j++) { data[j + -20] = (double)(data[j] * (double)1.001); @@ -11930,7 +14859,7 @@ public static void runDoubleM20() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -11938,7 +14867,7 @@ public static void runDoubleM20() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -11946,11 +14875,15 @@ public static void runDoubleM20() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -11959,6 +14892,10 @@ public static void runDoubleM20() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 160"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP20(double[] data) { for (int j = 0; j < RANGE - 20; j++) { data[j + 20] = (double)(data[j] * (double)1.001); @@ -11979,41 +14916,41 @@ public static void runDoubleP20() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM31(double[] data) { for (int j = 31; j < RANGE; j++) { @@ -12035,23 +14972,43 @@ public static void runDoubleM31() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 // positive byte_offset 248 can lead to cyclic dependency @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16", "MaxVectorSize", "<= 248"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP31(double[] data) { for (int j = 0; j < RANGE - 31; j++) { data[j + 31] = (double)(data[j] * (double)1.001); @@ -12072,22 +15029,42 @@ public static void runDoubleP31() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM32(double[] data) { for (int j = 32; j < RANGE; j++) { data[j + -32] = (double)(data[j] * (double)1.001); @@ -12108,7 +15085,7 @@ public static void runDoubleM32() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -12116,7 +15093,7 @@ public static void runDoubleM32() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -12124,7 +15101,7 @@ public static void runDoubleM32() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -12132,7 +15109,7 @@ public static void runDoubleM32() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -12140,7 +15117,7 @@ public static void runDoubleM32() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -12164,41 +15141,41 @@ public static void runDoubleP32() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM63(double[] data) { for (int j = 63; j < RANGE; j++) { @@ -12220,22 +15197,42 @@ public static void runDoubleM63() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP63(double[] data) { for (int j = 0; j < RANGE - 63; j++) { data[j + 63] = (double)(data[j] * (double)1.001); @@ -12256,22 +15253,42 @@ public static void runDoubleP63() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM64(double[] data) { for (int j = 64; j < RANGE; j++) { data[j + -64] = (double)(data[j] * (double)1.001); @@ -12292,7 +15309,7 @@ public static void runDoubleM64() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -12300,7 +15317,7 @@ public static void runDoubleM64() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -12308,7 +15325,7 @@ public static void runDoubleM64() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -12316,7 +15333,7 @@ public static void runDoubleM64() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -12324,7 +15341,7 @@ public static void runDoubleM64() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -12348,41 +15365,41 @@ public static void runDoubleP64() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM65(double[] data) { for (int j = 65; j < RANGE; j++) { @@ -12404,22 +15421,42 @@ public static void runDoubleM65() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP65(double[] data) { for (int j = 0; j < RANGE - 65; j++) { data[j + 65] = (double)(data[j] * (double)1.001); @@ -12440,22 +15477,42 @@ public static void runDoubleP65() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM128(double[] data) { for (int j = 128; j < RANGE; j++) { data[j + -128] = (double)(data[j] * (double)1.001); @@ -12476,7 +15533,7 @@ public static void runDoubleM128() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -12484,7 +15541,7 @@ public static void runDoubleM128() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -12492,7 +15549,7 @@ public static void runDoubleM128() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -12500,7 +15557,7 @@ public static void runDoubleM128() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -12508,7 +15565,7 @@ public static void runDoubleM128() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) @@ -12532,41 +15589,41 @@ public static void runDoubleP128() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Strict alignment not possible. - @IR(failOn = {IRNode.LOAD_VECTOR_D, IRNode.MUL_VD, IRNode.STORE_VECTOR}, - applyIf = {"AlignVector", "true"}, + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM129(double[] data) { for (int j = 129; j < RANGE; j++) { @@ -12588,22 +15645,42 @@ public static void runDoubleM129() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleP129(double[] data) { for (int j = 0; j < RANGE - 129; j++) { data[j + 129] = (double)(data[j] * (double)1.001); @@ -12624,22 +15701,42 @@ public static void runDoubleP129() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) // CPU: avx and avx2 -> vector_width: 32 -> elements in vector: 4 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) // CPU: avx512 -> vector_width: 64 -> elements in vector: 8 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"avx512", "true"}) // CPU: asimd -> vector_width: 16 -> elements in vector: 2 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // CPU: sve -> max vector_width: 256 -> max elements in vector: 32 @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) + // Expect alignment. + @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, + applyIfCPUFeature = {"sve", "true"}) public static void testDoubleM192(double[] data) { for (int j = 192; j < RANGE; j++) { data[j + -192] = (double)(data[j] * (double)1.001); @@ -12660,7 +15757,7 @@ public static void runDoubleM192() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"sse4.1", "true", "avx", "false"}) @@ -12668,7 +15765,7 @@ public static void runDoubleM192() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx512", "false"}) @@ -12676,7 +15773,7 @@ public static void runDoubleM192() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"avx512", "true"}) @@ -12684,7 +15781,7 @@ public static void runDoubleM192() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) @@ -12692,7 +15789,7 @@ public static void runDoubleM192() { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "false", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) - // Vectorize when strict alignment guaranteed. + // Expect alignment. @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_VD, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfAnd = {"AlignVector", "true", "MaxVectorSize", ">= 16"}, applyIfCPUFeature = {"sve", "true"}) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java index 80922aeffe9..752c8010468 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ /** * @test * @requires vm.compiler2.enabled - * @requires vm.cpu.features ~= ".*avx2.*" * @bug 8316679 8316594 * @summary In SuperWord::output, LoadVector can be moved before StoreVector, but only if it is proven to be safe. * @key randomness diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java index 78e97f26817..e32da89b8cd 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ /** * @test * @bug 8310886 - * @requires os.arch == "x86_64" | os.arch == "aarch64" * @summary Test MulAddS2I vectorization. * @library /test/lib / * @run driver compiler.loopopts.superword.TestMulAddS2I @@ -75,15 +74,14 @@ public static void compare(int[] out) { } @Test - @IR(applyIfCPUFeature = {"sse2", "true"}, applyIf = {"UseUnalignedLoadStores", "true"}, + @IR(applyIfCPUFeature = {"sse2", "true"}, + applyIfPlatform = {"64-bit", "true"}, counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) - @IR(applyIfCPUFeature = {"sse2", "true"}, applyIf = {"UseUnalignedLoadStores", "false"}, - failOn = {IRNode.MUL_ADD_VS2VI}, // Can only pack LoadS if UseUnalignedLoadStores is true (default if sse4.2) - counts = {IRNode.MUL_ADD_S2I, "> 0"}) - @IR(applyIfCPUFeature = {"asimd", "true"}, applyIf = {"MaxVectorSize", "16"}, // AD file requires vector_length = 16 - counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) - @IR(applyIfCPUFeature = {"avx512_vnni", "true"}, applyIf = {"UseUnalignedLoadStores", "true"}, - counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI_VNNI, "> 0"}) + @IR(applyIfCPUFeature = {"asimd", "true"}, + applyIf = {"MaxVectorSize", "16"}, // AD file requires vector_length = 16 + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"avx512_vnni", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI_VNNI, "> 0"}) public static int[] test() { int[] out = new int[ITER]; int[] out2 = new int[ITER]; diff --git a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java index 48bd723a13e..9e8ac6b013a 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java @@ -38,7 +38,7 @@ public class CheckLoopStripMining { public static void main(String args[]) throws Exception { - ProcessTools.executeTestJvm("-XX:+UnlockDiagnosticVMOptions", + ProcessTools.executeTestJava("-XX:+UnlockDiagnosticVMOptions", "-XX:+SafepointTimeout", "-XX:+SafepointALot", "-XX:+AbortVMOnSafepointTimeout", @@ -54,7 +54,7 @@ public static void main(String args[]) throws Exception { .shouldHaveExitValue(0) .stdoutShouldContain("sum: 715827882"); - ProcessTools.executeTestJvm("-XX:+UnlockDiagnosticVMOptions", + ProcessTools.executeTestJava("-XX:+UnlockDiagnosticVMOptions", "-XX:+SafepointTimeout", "-XX:+SafepointALot", "-XX:+AbortVMOnSafepointTimeout", diff --git a/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java b/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java index 13e36e049d1..d87f68efeee 100644 --- a/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java +++ b/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java @@ -81,7 +81,7 @@ private void runTest(String cmdPhases, List expectedPhases, String logFi options.add("-XX:CompileCommand=PrintIdealPhase," + getTestClass() + "::test," + cmdPhases); options.add(getTestClass()); - OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + OutputAnalyzer oa = ProcessTools.executeTestJava(options); if (valid) { oa.shouldHaveExitValue(0) .shouldContain("CompileCommand: PrintIdealPhase compiler/oracle/PrintIdealPhaseTest$TestMain.test const char* PrintIdealPhase = '"+cmdPhases.replace(',', ' ')+"'") diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java b/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java index b3be2c69820..d9f9aa3f7d4 100644 --- a/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java +++ b/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java @@ -105,7 +105,7 @@ private static void test(String include, String exclude) throws Exception { } options.add(getTestClass()); - OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + OutputAnalyzer oa = ProcessTools.executeTestJava(options); oa.reportDiagnosticSummary(); diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation.java b/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation.java index 1fb102acb07..358a5a0a6b3 100644 --- a/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation.java +++ b/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation.java @@ -56,7 +56,7 @@ private static void test(String include, String exclude) throws Exception { options.add("-XX:CompileCommand=PrintCompilation," + getTestMethod(include)); options.add(getTestClass()); - OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + OutputAnalyzer oa = ProcessTools.executeTestJava(options); oa.shouldHaveExitValue(0) .shouldContain(getTestMethod(include)) diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java b/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java index 3d68f107234..c0a99863fbf 100644 --- a/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java +++ b/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java @@ -55,7 +55,7 @@ private static void test(String include, String exclude) throws Exception { options.add("-XX:CompileCommand=MemStat," + getTestMethod(include) + ",print"); options.add(getTestClass()); - OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + OutputAnalyzer oa = ProcessTools.executeTestJava(options); // We expect two printouts for "PrintMemStat". A line at compilation time, and a line in a summary report // that is printed when we exit. Both use the typical ::name format but use / as separator and also diff --git a/test/hotspot/jtreg/compiler/print/PrintCompilation.java b/test/hotspot/jtreg/compiler/print/PrintCompilation.java index c04b2bf5206..3b3db304cef 100644 --- a/test/hotspot/jtreg/compiler/print/PrintCompilation.java +++ b/test/hotspot/jtreg/compiler/print/PrintCompilation.java @@ -47,7 +47,7 @@ public static void main(String[] args) throws Exception { options.add("-XX:CompileCommand=compileonly," + getTestClass() + "::*"); options.add(getTestClass()); - OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + OutputAnalyzer oa = ProcessTools.executeTestJava(options); oa.shouldHaveExitValue(0) .shouldContain(getTestMethod("method1")) diff --git a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java index df221959bb5..3daf12df879 100644 --- a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java +++ b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java @@ -261,7 +261,7 @@ static void run(TestConstantsInError test) throws Exception { c1Args.addAll(List.of("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-XX:+TracePatching")); c1Args.addAll(commonArgs); - OutputAnalyzer outputC1 = ProcessTools.executeTestJvm(c1Args) + OutputAnalyzer outputC1 = ProcessTools.executeTestJava(c1Args) .shouldHaveExitValue(0); test.process(outputC1, true); @@ -270,7 +270,7 @@ static void run(TestConstantsInError test) throws Exception { c2Args.add("-XX:-TieredCompilation"); c2Args.addAll(commonArgs); - OutputAnalyzer outputC2 = ProcessTools.executeTestJvm(c2Args) + OutputAnalyzer outputC2 = ProcessTools.executeTestJava(c2Args) .shouldHaveExitValue(0); test.process(outputC2, false); diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index 689c7c8cc2f..d5bf13e8fc2 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -61,10 +61,11 @@ public class IntrinsicPredicates { public static final BooleanSupplier MD5_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", null, null), + new OrPredicate(new CPUSpecificPredicate("riscv64.*", null, null), // x86 variants new OrPredicate(new CPUSpecificPredicate("amd64.*", null, null), new OrPredicate(new CPUSpecificPredicate("i386.*", null, null), - new CPUSpecificPredicate("x86.*", null, null)))); + new CPUSpecificPredicate("x86.*", null, null))))); public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha1" }, null), diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java index 0e275e96794..35b88933219 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java @@ -102,7 +102,7 @@ static public void main(String[] args) throws Exception { String[] arg = {"--enable-preview", "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,TestArrayAccessDeopt::test*", "-XX:-UseArrayLoadStoreProfile", "-XX:+TraceDeoptimization", "-Xbatch", "-XX:-MonomorphicArrayCheck", "-Xmixed", "-XX:+ProfileInterpreter", "TestArrayAccessDeopt", "run"}; - OutputAnalyzer oa = ProcessTools.executeTestJvm(arg); + OutputAnalyzer oa = ProcessTools.executeTestJava(arg); String output = oa.getOutput(); oa.shouldNotContain("Uncommon trap occurred"); } else { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java index ec199317429..1c006291aba 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java @@ -1901,7 +1901,7 @@ private static void enumerateVMOptions() throws Exception { continue; } - OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); + OutputAnalyzer oa = ProcessTools.executeTestJava(cmds); String output = oa.getOutput(); oa.shouldHaveExitValue(0); System.out.println(output); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java index ad34b4193d9..4ede3daa649 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java @@ -53,7 +53,7 @@ static public void main(String[] args) throws Exception { // Run test in new VM instance String[] arg = {"--enable-preview", "-XX:+InlineTypePassFieldsAsArgs", "TestUnresolvedInlineClass", "run"}; - OutputAnalyzer oa = ProcessTools.executeTestJvm(arg); + OutputAnalyzer oa = ProcessTools.executeTestJava(arg); // Verify that a warning is printed String output = oa.getOutput(); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java index eb25472370f..4f9f8ca3bd2 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java @@ -37,43 +37,43 @@ public class TestVectorErgonomics { public static void main(String[] args) throws Throwable { - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorReboxing=true"); - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorAggressiveReboxing=true"); - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:-EnableVectorReboxing", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableVectorReboxing", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorReboxing=false") .shouldContain("EnableVectorAggressiveReboxing=false"); - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:-EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorAggressiveReboxing=false"); - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:-EnableVectorSupport", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableVectorSupport", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorSupport=false") .shouldContain("EnableVectorReboxing=false") .shouldContain("EnableVectorAggressiveReboxing=false"); - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:-EnableVectorSupport", "-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableVectorSupport", "-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorSupport=false") .shouldContain("EnableVectorReboxing=false") .shouldContain("EnableVectorAggressiveReboxing=false"); - ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", - "-XX:-EnableVectorSupport", "-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version") + ProcessTools.executeTestJava("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableVectorSupport", "-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version") .shouldHaveExitValue(0) .shouldContain("EnableVectorSupport=false") .shouldContain("EnableVectorReboxing=false") diff --git a/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java b/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java index 889cc68f876..76251ba99c8 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,24 +23,17 @@ /** * @test - * @bug 8257531 + * @bug 8257531 8310190 * @summary Test vectorization for Buffer operations. * @library /test/lib / - * - * @requires vm.flagless - * @requires vm.compiler2.enabled & vm.debug == true - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" - * - * @run driver compiler.vectorization.TestBufferVectorization array - * @run driver compiler.vectorization.TestBufferVectorization arrayOffset - * @run driver compiler.vectorization.TestBufferVectorization buffer - * @run driver compiler.vectorization.TestBufferVectorization bufferHeap - * @run driver compiler.vectorization.TestBufferVectorization bufferDirect - * @run driver compiler.vectorization.TestBufferVectorization arrayView + * @requires vm.compiler2.enabled + * @run driver compiler.vectorization.TestBufferVectorization */ package compiler.vectorization; +import compiler.lib.ir_framework.*; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -48,205 +41,196 @@ import java.nio.ByteOrder; import java.nio.IntBuffer; -import jdk.test.lib.Platform; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; - public class TestBufferVectorization { - final static int N = 500; - final static int ITER = 1000; - final static IntBuffer buffer = IntBuffer.allocate(N); - final static int offset = buffer.arrayOffset(); - final static IntBuffer heap_buffer_byte_to_int = ByteBuffer.allocate(N * Integer.BYTES).order(ByteOrder.nativeOrder()).asIntBuffer(); - final static IntBuffer direct_buffer_byte_to_int = ByteBuffer.allocateDirect(N * Integer.BYTES).order(ByteOrder.nativeOrder()).asIntBuffer(); + final static int N = 1024*16; + static int offset = 0; final static VarHandle VH_arr_view = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.nativeOrder()).withInvokeExactBehavior(); - final static String arch = System.getProperty("os.arch"); - interface Test { - void init(); - void run(); - void verify(); + public static void main(String[] args) { + TestFramework.run(); } - static class TestArray implements Test { - final int[] array = new int[N]; + @Run(test = "testArray") + public static void runArray() { + int[] array = new int[N]; - public void init() { - for (int k = 0; k < array.length; k++) { - array[k] = k; - } + for (int k = 0; k < array.length; k++) { + array[k] = k; } - public void run() { - for(int k = 0; k < array.length; k++) { - array[k] += 1; + testArray(array); + + for(int k = 0; k < array.length; k++) { + if (array[k] != (k + 1)) { + throw new RuntimeException(" Invalid result: array[" + k + "]: " + array[k] + " != " + (k + 1)); } } + } - public void verify() { - init(); // reset - run(); // run compiled code - for(int k = 0; k < array.length; k++) { - if (array[k] != (k + 1)) { - throw new RuntimeException(" Invalid result: array[" + k + "]: " + array[k] + " != " + (k + 1)); - } - } + @Test + @IR(counts = {IRNode.REPLICATE_I, ">0", + IRNode.LOAD_VECTOR_I, ">0", + IRNode.ADD_VI, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public static void testArray(int[] array) { + for(int k = 0; k < array.length; k++) { + array[k] += 1; } } - static class TestArrayOffset implements Test { - final int offset; - final int[] array = new int[N]; + @Run(test = "testArrayOffset") + public static void runArrayOffset() { + // Moving offset between 0..255 + offset = (offset + 1) % 256; - public TestArrayOffset(int off) { - offset = off; - } + int[] array = new int[N]; - public void init() { - for (int k = 0; k < array.length; k++) { - array[k] = k; - } + for (int k = 0; k < array.length; k++) { + array[k] = k; } - public void run() { - int l = array.length - offset; - for(int k = 0; k < l; k++) { - array[k + offset] += 1; - } - } + testArrayOffset(array, offset); - public void verify() { - init(); // reset - run(); // run compiled code - int l = array.length - offset; - for(int k = 0; k < l; k++) { - if (array[k] != (k + 1)) { - throw new RuntimeException(" Invalid result: arrayOffset[" + k + "]: " + array[k] + " != " + (k + 1)); - } + int l = array.length - offset; + for(int k = 0; k < offset; k++) { + if (array[k] != k) { + throw new RuntimeException(" Invalid result: arrayOffset[" + k + "]: " + array[k] + " != " + (k + 1)); } - for(int k = l; k < array.length; k++) { - if (array[k] != k) { - throw new RuntimeException(" Invalid result: arrayOffset[" + k + "]: " + array[k] + " != " + k); - } + } + for(int k = offset; k < array.length; k++) { + if (array[k] != (k + 1)) { + throw new RuntimeException(" Invalid result: arrayOffset[" + k + "]: " + array[k] + " != " + k); } } } - static class TestBuffer implements Test { - final IntBuffer buffer; - - public TestBuffer(IntBuffer buf) { - buffer = buf; - } - - public void init() { - for (int k = 0; k < buffer.limit(); k++) { - buffer.put(k, k); - } + @Test + @IR(counts = {IRNode.REPLICATE_I, ">0", + IRNode.LOAD_VECTOR_I, ">0", + IRNode.ADD_VI, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public static void testArrayOffset(int[] array, int offset) { + int l = array.length - offset; + for(int k = 0; k < l; k++) { + array[k + offset] += 1; } + } - public void run() { - for (int k = 0; k < buffer.limit(); k++) { - buffer.put(k, buffer.get(k) + 1); - } - } + @Run(test = "testBuffer") + public static void runBuffer() { + IntBuffer buffer = IntBuffer.allocate(N); + initBuffer(buffer); + testBuffer(buffer); + verifyBuffer(buffer); + } - public void verify() { - init(); // reset - run(); // run compiled code - for(int k = 0; k < buffer.limit(); k++) { - if (buffer.get(k) != (k + 1)) { - throw new RuntimeException(" Invalid result: buffer.get(" + k + "): " + buffer.get(k) + " != " + (k + 1)); - } - } + @Test + @IR(counts = {IRNode.REPLICATE_I, ">0", + IRNode.LOAD_VECTOR_I, ">0", + IRNode.ADD_VI, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public static void testBuffer(IntBuffer buffer) { + for (int k = 0; k < buffer.limit(); k++) { + buffer.put(k, buffer.get(k) + 1); } } - static class TestArrayView implements Test { - final byte[] b_arr = new byte[N * Integer.BYTES]; + @Run(test = "testBufferHeap") + public static void runBufferHeap() { + IntBuffer buffer = ByteBuffer.allocate(N * Integer.BYTES).order(ByteOrder.nativeOrder()).asIntBuffer(); + initBuffer(buffer); + testBufferHeap(buffer); + verifyBuffer(buffer); + } - public void init() { - for (int k = 0; k < N; k++) { - VH_arr_view.set(b_arr, k, k); - } + @Test + @IR(counts = {IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_ANY, ">0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // VECTOR_SIZE_ANY: Unrolling does not always seem to go far enough to reach maximum vector size. + // This looks like a BUG. + // AlignVector: Buffer get/put have an invariant that is in bytes (LoadL in ByteBufferAsIntBufferL::byteOffset). + // This makes sense: we are accessing a byte buffer. But to be able to align the 4 byte ints, + // we would require to know that the invariant is a multiple of 4. Without that, we cannot + // guarantee alignment by adjusting the limit of the pre-loop with a stride of 4 bytes. + // 64-bit: bufferHeap uses Long type for memory accesses which are not vectorized in 32-bit VM + public static void testBufferHeap(IntBuffer buffer) { + for (int k = 0; k < buffer.limit(); k++) { + buffer.put(k, buffer.get(k) + 1); } + } - public void run() { - for (int k = 0; k < b_arr.length; k += 4) { - int v = (int) VH_arr_view.get(b_arr, k); - VH_arr_view.set(b_arr, k, v + 1); - } + @Run(test = "testBufferDirect") + public static void runBufferDirect() { + IntBuffer buffer = ByteBuffer.allocateDirect(N * Integer.BYTES).order(ByteOrder.nativeOrder()).asIntBuffer(); + initBuffer(buffer); + testBufferDirect(buffer); + verifyBuffer(buffer); + } + + @Test + // bufferDirect uses Unsafe memory accesses which are not vectorized currently + // We find a CastX2P in pointer analysis (VPointer) + public static void testBufferDirect(IntBuffer buffer) { + for (int k = 0; k < buffer.limit(); k++) { + buffer.put(k, buffer.get(k) + 1); } + } - public void verify() { - init(); // reset - // Save initial INT values - final int[] i_arr = new int[N]; - for (int k = 0; k < i_arr.length; k++) { - i_arr[k] = (int) VH_arr_view.get(b_arr, k * Integer.BYTES); - } - run(); // run compiled code - for (int k = 0; k < i_arr.length; k++) { - int v = (int) VH_arr_view.get(b_arr, k * Integer.BYTES); - if (v != (i_arr[k] + 1)) { - throw new RuntimeException(" Invalid result: VH_arr_view.get(b_arr, " + (k * Integer.BYTES) + "): " + v + " != " + (i_arr[k] + 1)); - } - } + public static void initBuffer(IntBuffer buffer) { + for (int k = 0; k < buffer.limit(); k++) { + buffer.put(k, k); } } - public static void main(String[] args) { - if (args.length == 0) { - throw new RuntimeException(" Missing test name: array, arrayOffset, buffer, bufferHeap, bufferDirect, arrayView"); - } else if (args.length == 1) { - verify_vectors(args[0]); - } else { - Test te = switch (args[0]) { - case "array" -> new TestArray(); - case "arrayOffset" -> new TestArrayOffset(offset); - case "buffer" -> new TestBuffer(buffer); - case "bufferHeap" -> new TestBuffer(heap_buffer_byte_to_int); - case "bufferDirect" -> new TestBuffer(direct_buffer_byte_to_int); - case "arrayView" -> new TestArrayView(); - default -> throw new RuntimeException(" Unknown test: " + args[0]); - }; - - te.init(); - for (int i = 0; i < ITER; i++) { - te.run(); + public static void verifyBuffer(IntBuffer buffer) { + for(int k = 0; k < buffer.limit(); k++) { + if (buffer.get(k) != (k + 1)) { + throw new RuntimeException(" Invalid result: buffer.get(" + k + "): " + buffer.get(k) + " != " + (k + 1)); } - te.verify(); } - } - static void verify_vectors(String testName) { - ProcessBuilder pb; - OutputAnalyzer out; - try { - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:-BackgroundCompilation", - "-XX:+TraceNewVectors", - "compiler.vectorization.TestBufferVectorization", - testName, - "run"); - out = new OutputAnalyzer(pb.start()); - } catch (Exception e) { - throw new RuntimeException(" Exception launching Java process: " + e); - } + @Run(test = "testArrayView") + public static void runArrayView() { + byte[] b_arr = new byte[N * Integer.BYTES]; - out.shouldHaveExitValue(0); + for (int k = 0; k < N; k++) { + VH_arr_view.set(b_arr, k, k); + } - if (testName.equals("bufferDirect")) { - return; // bufferDirect uses Unsafe memory accesses which are not vectorized currently + // Save initial INT values + int[] i_arr = new int[N]; + for (int k = 0; k < i_arr.length; k++) { + i_arr[k] = (int) VH_arr_view.get(b_arr, k * Integer.BYTES); } + testArrayView(b_arr); - if (testName.equals("bufferHeap") && (Platform.is32bit())) { - return; // bufferHeap uses Long type for memory accesses which are not vectorized in 32-bit VM + for (int k = 0; k < i_arr.length; k++) { + int v = (int) VH_arr_view.get(b_arr, k * Integer.BYTES); + if (v != (i_arr[k] + 1)) { + throw new RuntimeException(" Invalid result: VH_arr_view.get(b_arr, " + (k * Integer.BYTES) + "): " + v + " != " + (i_arr[k] + 1)); + } } + } - out.shouldContain("Replicate"); - out.shouldContain("LoadVector"); - out.shouldContain("AddVI"); - out.shouldContain("StoreVector"); + @Test + @IR(counts = {IRNode.REPLICATE_I, ">0", + IRNode.LOAD_VECTOR_I, ">0", + IRNode.ADD_VI, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public static void testArrayView(byte[] b_arr) { + for (int k = 0; k < b_arr.length; k += 4) { + int v = (int) VH_arr_view.get(b_arr, k); + VH_arr_view.set(b_arr, k, v + 1); + } } } diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index fbea62f81f8..5b7f96112b9 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -117,7 +117,9 @@ private static void checkContainerInfo(OutputAnalyzer out) throws Exception { "Maximum Memory Usage", "memory_max_usage_in_bytes", "maximum number of tasks", - "current number of tasks" + "current number of tasks", + "rss_usage_in_bytes", + "cache_usage_in_bytes" }; for (String s : expectedToContain) { diff --git a/test/hotspot/jtreg/gc/TestAgeOutput.java b/test/hotspot/jtreg/gc/TestAgeOutput.java index fa4445e34bb..cbee132a0af 100644 --- a/test/hotspot/jtreg/gc/TestAgeOutput.java +++ b/test/hotspot/jtreg/gc/TestAgeOutput.java @@ -66,7 +66,7 @@ public static void checkPattern(String pattern, String what) throws Exception { } public static void runTest(String gcArg) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", @@ -75,7 +75,6 @@ public static void runTest(String gcArg) throws Exception { "-Xmx10M", "-Xlog:gc+age=trace", GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/TestAllocateHeapAt.java index 8daf0bbcdc7..d1e96751ab8 100644 --- a/test/hotspot/jtreg/gc/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/TestAllocateHeapAt.java @@ -36,13 +36,12 @@ public class TestAllocateHeapAt { public static void main(String args[]) throws Exception { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeTestJava( "-XX:AllocateHeapAt=" + System.getProperty("test.dir", "."), "-Xlog:gc+heap=info", "-Xmx32m", "-Xms32m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println("Output:\n" + output.getOutput()); diff --git a/test/hotspot/jtreg/gc/TestAllocateHeapAtError.java b/test/hotspot/jtreg/gc/TestAllocateHeapAtError.java index 372437b8898..28e2f71d09d 100644 --- a/test/hotspot/jtreg/gc/TestAllocateHeapAtError.java +++ b/test/hotspot/jtreg/gc/TestAllocateHeapAtError.java @@ -45,13 +45,12 @@ public static void main(String args[]) throws Exception { f = new File(test_dir, UUID.randomUUID().toString()); } while(f.exists()); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeTestJava( "-XX:AllocateHeapAt=" + f.getName(), "-Xlog:gc+heap=info", "-Xmx32m", "-Xms32m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println("Output:\n" + output.getOutput()); diff --git a/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java b/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java index b2d2f1e429d..d8d1b4bd88d 100644 --- a/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java +++ b/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java @@ -60,8 +60,7 @@ public static void main(String args[]) throws Exception { "-Xlog:gc+heap=info", "-version"}); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(flags); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeTestJava(flags); System.out.println("Output:\n" + output.getOutput()); diff --git a/test/hotspot/jtreg/gc/TestCardTablePageCommits.java b/test/hotspot/jtreg/gc/TestCardTablePageCommits.java index c468a771076..6c10dd0100e 100644 --- a/test/hotspot/jtreg/gc/TestCardTablePageCommits.java +++ b/test/hotspot/jtreg/gc/TestCardTablePageCommits.java @@ -42,12 +42,11 @@ public static void main(String args[]) throws Exception { // because of 8kB pages, assume 4 KB pages for all other CPUs. String Xmx = "-Xmx4m"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( Xmx, "-XX:NativeMemoryTracking=detail", "-XX:+UseParallelGC", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/TestFillerObjectInstantiation.java b/test/hotspot/jtreg/gc/TestFillerObjectInstantiation.java index bec7c4858f5..edb63f88af2 100644 --- a/test/hotspot/jtreg/gc/TestFillerObjectInstantiation.java +++ b/test/hotspot/jtreg/gc/TestFillerObjectInstantiation.java @@ -45,6 +45,6 @@ private static void testInstantiationFails(String classname) throws Exception { public static void main(String[] args) throws Exception { testInstantiationFails("jdk.internal.vm.FillerObject"); - testInstantiationFails("jdk.internal.vm.FillerArray"); + testInstantiationFails("jdk.internal.vm.FillerElement"); } } diff --git a/test/hotspot/jtreg/gc/TestNumWorkerOutput.java b/test/hotspot/jtreg/gc/TestNumWorkerOutput.java index fd48c5a85d0..c4c0dce0c99 100644 --- a/test/hotspot/jtreg/gc/TestNumWorkerOutput.java +++ b/test/hotspot/jtreg/gc/TestNumWorkerOutput.java @@ -58,7 +58,7 @@ public static void checkPatternOnce(String pattern, String what) throws Exceptio } public static void runTest(String gcArg) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", @@ -67,7 +67,6 @@ public static void runTest(String gcArg) throws Exception { "-Xmx10M", "-XX:+PrintGCDetails", GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java b/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java index c5c4854946d..8dfefcb7d95 100644 --- a/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java +++ b/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java @@ -48,9 +48,7 @@ private static void runTest(boolean shouldSucceed, String... extraArgs) throws E Collections.addAll(testArguments, extraArgs); testArguments.add("-version"); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(testArguments); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeTestJava(testArguments); System.out.println(output.getStderr()); diff --git a/test/hotspot/jtreg/gc/TestSmallHeap.java b/test/hotspot/jtreg/gc/TestSmallHeap.java index a9b32eb81c8..fd6c5860f01 100644 --- a/test/hotspot/jtreg/gc/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/TestSmallHeap.java @@ -96,12 +96,11 @@ public static void main(String[] args) throws Exception { private static void verifySmallHeapSize(String gc, long expectedMaxHeap) throws Exception { long minMaxHeap = 4 * 1024 * 1024; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( gc, "-Xmx" + minMaxHeap, "-XX:+PrintFlagsFinal", VerifyHeapSize.class.getName()); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); expectedMaxHeap = Math.max(expectedMaxHeap, minMaxHeap); diff --git a/test/hotspot/jtreg/gc/TestVerifyDuringStartup.java b/test/hotspot/jtreg/gc/TestVerifyDuringStartup.java index 4ad9f9675d9..e651295d5b5 100644 --- a/test/hotspot/jtreg/gc/TestVerifyDuringStartup.java +++ b/test/hotspot/jtreg/gc/TestVerifyDuringStartup.java @@ -37,13 +37,12 @@ public class TestVerifyDuringStartup { public static void main(String args[]) throws Exception { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeTestJava( "-XX:-UseTLAB", "-XX:+UnlockDiagnosticVMOptions", "-XX:+VerifyDuringStartup", "-Xlog:gc+verify=debug", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println("Output:\n" + output.getOutput()); diff --git a/test/hotspot/jtreg/gc/TestVerifySilently.java b/test/hotspot/jtreg/gc/TestVerifySilently.java index b7b07a1eb8e..2f245f5eed2 100644 --- a/test/hotspot/jtreg/gc/TestVerifySilently.java +++ b/test/hotspot/jtreg/gc/TestVerifySilently.java @@ -57,8 +57,7 @@ private static OutputAnalyzer runTest(boolean verifySilently) throws Exception { "-XX:+VerifyAfterGC", (verifySilently ? "-Xlog:gc":"-Xlog:gc+verify=debug"), TestVerifySilentlyRunSystemGC.class.getName()}); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(vmOpts); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(vmOpts); System.out.println("Output:\n" + output.getOutput()); return output; diff --git a/test/hotspot/jtreg/gc/TestVerifySubSet.java b/test/hotspot/jtreg/gc/TestVerifySubSet.java index 5aa8cc3eb13..08cddc74a00 100644 --- a/test/hotspot/jtreg/gc/TestVerifySubSet.java +++ b/test/hotspot/jtreg/gc/TestVerifySubSet.java @@ -59,8 +59,7 @@ private static OutputAnalyzer runTest(String subset) throws Exception { "-Xlog:gc+verify=debug", "-XX:VerifySubSet="+subset, TestVerifySubSetRunSystemGC.class.getName()}); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(vmOpts); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(vmOpts); System.out.println("Output:\n" + output.getOutput()); return output; diff --git a/test/hotspot/jtreg/gc/arguments/GCArguments.java b/test/hotspot/jtreg/gc/arguments/GCArguments.java index c59a14954bf..3908ce17966 100644 --- a/test/hotspot/jtreg/gc/arguments/GCArguments.java +++ b/test/hotspot/jtreg/gc/arguments/GCArguments.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; /** @@ -81,4 +82,20 @@ static public ProcessBuilder createTestJavaProcessBuilder(List arguments static public ProcessBuilder createTestJavaProcessBuilder(String... arguments) { return ProcessTools.createTestJavaProcessBuilder(withDefaults(arguments)); } + + static public OutputAnalyzer executeLimitedTestJava(List arguments) throws Exception { + return executeLimitedTestJava(arguments.toArray(String[]::new)); + } + + static public OutputAnalyzer executeLimitedTestJava(String... arguments) throws Exception { + return ProcessTools.executeLimitedTestJava(withDefaults(arguments)); + } + + static public OutputAnalyzer executeTestJava(List arguments) throws Exception { + return executeTestJava(arguments.toArray(String[]::new)); + } + + static public OutputAnalyzer executeTestJava(String... arguments) throws Exception { + return ProcessTools.executeTestJava(withDefaults(arguments)); + } } diff --git a/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java b/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java index d01773fd711..4ed673a40fe 100644 --- a/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java +++ b/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java @@ -65,11 +65,9 @@ public static void main(String args[]) throws Exception { " *bool +UseParallelGC *= *true +\\{product\\} *\\{command line\\}"; private static void testFlag() throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeTestJava( option, heapSizeOption, "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); String value = output.firstMatch(parallelGCPattern); diff --git a/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java b/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java index 0b6dce0fc0e..c1975d6b692 100644 --- a/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java @@ -41,17 +41,13 @@ public class TestCompressedClassFlags { public static void main(String[] args) throws Exception { if (Platform.is64bit()) { - OutputAnalyzer output = runJava("-XX:CompressedClassSpaceSize=1g", - "-XX:-UseCompressedClassPointers", - "-version"); + OutputAnalyzer output = GCArguments.executeTestJava( + "-XX:CompressedClassSpaceSize=1g", + "-XX:-UseCompressedClassPointers", + "-version"); output.shouldContain("warning"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } } - - private static OutputAnalyzer runJava(String ... args) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(args); - return new OutputAnalyzer(pb.start()); - } } diff --git a/test/hotspot/jtreg/gc/arguments/TestDisableDefaultGC.java b/test/hotspot/jtreg/gc/arguments/TestDisableDefaultGC.java index e8e4552da01..0828622fa7a 100644 --- a/test/hotspot/jtreg/gc/arguments/TestDisableDefaultGC.java +++ b/test/hotspot/jtreg/gc/arguments/TestDisableDefaultGC.java @@ -40,14 +40,13 @@ public class TestDisableDefaultGC { public static void main(String[] args) throws Exception { // Start VM, disabling all possible default GCs - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder("-XX:-UseSerialGC", - "-XX:-UseParallelGC", - "-XX:-UseG1GC", - "-XX:-UseZGC", - "-XX:+UnlockExperimentalVMOptions", - "-XX:-UseShenandoahGC", - "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava("-XX:-UseSerialGC", + "-XX:-UseParallelGC", + "-XX:-UseG1GC", + "-XX:-UseZGC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:-UseShenandoahGC", + "-version"); output.shouldMatch("Garbage collector not selected"); output.shouldHaveExitValue(1); } diff --git a/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java b/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java index 21a4eddb410..c5f595e7a1a 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java @@ -78,8 +78,7 @@ private static void runG1ConcMarkStepDurationMillisTest(String expectedValue, in Collections.addAll(vmOpts, "-XX:+UseG1GC", "-XX:G1ConcMarkStepDurationMillis="+expectedValue, "-XX:+PrintFlagsFinal", "-version"); - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(vmOpts); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(vmOpts); output.shouldHaveExitValue(expectedResult == PASS ? 0 : 1); String stdout = output.getStdout(); diff --git a/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java b/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java index 91be97782f5..f82d2b31711 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java @@ -69,8 +69,7 @@ private static void runG1ConcRefinementThreadsTest(String[] passedOpts, } Collections.addAll(vmOpts, "-XX:+UseG1GC", "-XX:+PrintFlagsFinal", "-version"); - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(vmOpts); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(vmOpts); output.shouldHaveExitValue(0); String stdout = output.getStdout(); diff --git a/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java b/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java index 0d63dec0c26..5ecd27e24e8 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java @@ -53,8 +53,7 @@ private static void checkG1HeapRegionSize(String[] flags, int expectedValue, int flagList.add("-XX:+PrintFlagsFinal"); flagList.add("-version"); - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(flagList); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(flagList); output.shouldHaveExitValue(exitValue); if (exitValue == 0) { diff --git a/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java b/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java index 875e995374a..e8ee2598c9a 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java @@ -63,8 +63,7 @@ private static final class OptionDescription { }; private static void check(String flag, boolean is_valid) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder("-XX:+UseG1GC", flag, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava("-XX:+UseG1GC", flag, "-version"); if (is_valid) { output.shouldHaveExitValue(0); } else { diff --git a/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java b/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java index 84483f39272..63b9d782c06 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java @@ -48,8 +48,7 @@ private static void checkG1RemSetFlags(String[] flags, int exitValue) throws Exc flagList.add("-XX:+PrintFlagsFinal"); flagList.add("-version"); - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(flagList); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(flagList); output.shouldHaveExitValue(exitValue); } diff --git a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java index 19ecb181418..c8eaa0f46e3 100644 --- a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java +++ b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java @@ -48,11 +48,10 @@ enum Validation { } private static void testMinMaxFreeRatio(String min, String max, Validation type) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeTestJava( "-Xminf" + min, "-Xmaxf" + max, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (type) { case VALID: diff --git a/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java b/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java index 7bf78a001bf..07a9065cee1 100644 --- a/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java +++ b/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java @@ -41,14 +41,13 @@ public class TestInitialTenuringThreshold { public static void runWithThresholds(int initial, int max, boolean shouldfail) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeTestJava( "-XX:+UseParallelGC", "-XX:InitialTenuringThreshold=" + String.valueOf(initial), "-XX:MaxTenuringThreshold=" + String.valueOf(max), "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); if (shouldfail) { output.shouldHaveExitValue(1); } else { @@ -58,14 +57,13 @@ public static void runWithThresholds(int initial, int max, boolean shouldfail) t public static void main(String args[]) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeTestJava( // some value below the default value of InitialTenuringThreshold of 7 "-XX:+UseParallelGC", "-XX:MaxTenuringThreshold=1", "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); // successful tests runWithThresholds(0, 10, false); diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java index 3a5d472f9f8..5af005063c1 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java @@ -115,9 +115,8 @@ private static long align_up(long value, long alignment) { } private static void getNewOldSize(String gcflag, long[] values) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(gcflag, + OutputAnalyzer output = GCArguments.executeTestJava(gcflag, "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String stdout = output.getStdout(); @@ -208,8 +207,7 @@ public static OutputAnalyzer runWhiteBoxTest(String[] vmargs, String classname, finalargs.add(classname); finalargs.addAll(Arrays.asList(arguments)); - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(finalargs.toArray(String[]::new)); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(finalargs.toArray(String[]::new)); output.shouldHaveExitValue(0); return output; @@ -308,8 +306,7 @@ private static void shouldContainOrNot(OutputAnalyzer output, boolean contains, } private static void expect(String[] flags, boolean hasWarning, boolean hasError, int errorcode) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(flags); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(flags); shouldContainOrNot(output, hasWarning, "Warning"); shouldContainOrNot(output, hasError, "Error"); output.shouldHaveExitValue(errorcode); diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java b/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java index 7e91fe60cfb..11729aa5827 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java @@ -98,8 +98,7 @@ public static void positiveTest(int minRatio, boolean useXminf, Boolean.toString(shrinkHeapInSteps) ); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(0); } @@ -123,8 +122,7 @@ public static void negativeTest(int minRatio, boolean useXminf, "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", "-version" ); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(1); analyzer.shouldContain("Error: Could not create the Java Virtual Machine."); } diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java index f2214b8b0cf..ff6c3127640 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java @@ -95,8 +95,7 @@ private static String getMaxNewSize(String[] flags) throws Exception { finalargs.add("-XX:+PrintFlagsFinal"); finalargs.add("-version"); - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder(finalargs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeTestJava(finalargs); output.shouldHaveExitValue(0); String stdout = output.getStdout(); return getFlagValue("MaxNewSize", stdout); diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java b/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java index 4c66afd5cf5..13bb36ecc43 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java @@ -61,8 +61,7 @@ private static void checkMaxRAMSize(long maxram, int maxrampercent, boolean forc args.add("-XX:+PrintFlagsFinal"); args.add("-version"); - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(args); output.shouldHaveExitValue(0); String stdout = output.getStdout(); @@ -84,8 +83,7 @@ private static long getHeapBaseMinAddress() throws Exception { args.add("-XX:+PrintFlagsFinal"); args.add("-version"); - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(args); output.shouldHaveExitValue(0); String stdout = output.getStdout(); return (new Long(getFlagValue("HeapBaseMinAddress", stdout)).longValue()); diff --git a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java index 83f564b98a5..d3a51c40b61 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java @@ -102,8 +102,7 @@ public static void testSurvivorRatio(int survivorRatio, Boolean.toString(useAdaptiveSizePolicy) ); vmOptions.removeIf((String p) -> p.isEmpty()); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java b/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java index 9076005fa86..6eff65f3fa8 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java @@ -82,8 +82,7 @@ public static void testNewRatio(int ratio, LinkedList options) throws Ex Integer.toString(ratio) ); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(0); System.out.println(analyzer.getOutput()); } diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java index 3c3aff980dd..8fc522f8be8 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java @@ -133,7 +133,7 @@ public static void testVMOptions(long newSize, long maxNewSize, long heapSize, long maxHeapSize, long expectedNewSize, long expectedMaxNewSize, LinkedList options, boolean failureExpected) throws Exception { - OutputAnalyzer analyzer = startVM(options, newSize, maxNewSize, heapSize, maxHeapSize, expectedNewSize, expectedMaxNewSize); + OutputAnalyzer analyzer = executeLimitedTestJava(options, newSize, maxNewSize, heapSize, maxHeapSize, expectedNewSize, expectedMaxNewSize); if (failureExpected) { analyzer.shouldHaveExitValue(1); @@ -144,7 +144,7 @@ public static void testVMOptions(long newSize, long maxNewSize, } } - private static OutputAnalyzer startVM(LinkedList options, + private static OutputAnalyzer executeLimitedTestJava(LinkedList options, long newSize, long maxNewSize, long heapSize, long maxHeapSize, long expectedNewSize, long expectedMaxNewSize) throws Exception, IOException { @@ -166,9 +166,7 @@ private static OutputAnalyzer startVM(LinkedList options, Long.toString(maxHeapSize) ); vmOptions.removeIf(String::isEmpty); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); - return analyzer; + return GCArguments.executeLimitedTestJava(vmOptions); } /** diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java index 82e98429100..583176dfc69 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java @@ -65,14 +65,13 @@ public static void main(String[] args) throws Exception { } static void runNewSizeThreadIncreaseTest(String expectedValue, boolean isNewsizeChanged) throws Exception { - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder("-XX:+UseSerialGC", - "-Xms96M", - "-Xmx128M", - "-XX:NewRatio=2", - "-Xlog:gc+heap+ergo=debug", - "-XX:NewSizeThreadIncrease="+expectedValue, - GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava("-XX:+UseSerialGC", + "-Xms96M", + "-Xmx128M", + "-XX:NewRatio=2", + "-Xlog:gc+heap+ergo=debug", + "-XX:NewSizeThreadIncrease="+expectedValue, + GCTest.class.getName()); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java index ca45def0b2b..ee1e73f9550 100644 --- a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java @@ -161,8 +161,7 @@ private static void runTenuringFlagsConsistencyTest(String[] tenuringFlags, } Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(vmOpts); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(vmOpts); if (shouldFail) { output.shouldHaveExitValue(1); diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java index 1055f4fee13..8cc3292b25f 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java @@ -56,10 +56,9 @@ public static void main(String args[]) throws Exception { private static final String printFlagsFinalPattern = " *uint *" + flagName + " *:?= *(\\d+) *\\{product\\} *"; public static void testDefaultValue() throws Exception { - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeLimitedTestJava( "-XX:+UnlockExperimentalVMOptions", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); String value = output.firstMatch(printFlagsFinalPattern, 1); try { @@ -94,12 +93,11 @@ public static void testFlags() throws Exception { for (String gc : supportedGC) { // Make sure the VM does not allow ParallelGCThreads set to 0 - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeLimitedTestJava( "-XX:+Use" + gc + "GC", "-XX:ParallelGCThreads=0", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(1); // Do some basic testing to ensure the flag updates the count @@ -124,8 +122,7 @@ public static void testFlags() throws Exception { } public static long getParallelGCThreadCount(String... flags) throws Exception { - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(flags); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(flags); output.shouldHaveExitValue(0); String stdout = output.getStdout(); return FlagsValue.getFlagLongValue("ParallelGCThreads", stdout); diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java b/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java index d47d277e30b..40dfc4dc7fb 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java @@ -77,9 +77,7 @@ private static void testFlag(String[] args, boolean expectedTrue) throws Excepti result.addAll(Arrays.asList(args)); result.add("-XX:+PrintFlagsFinal"); result.add("-version"); - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(result); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(result); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java index a48f21c957b..fb4787f452f 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java +++ b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java @@ -44,12 +44,11 @@ public static void assertVMOption(OutputAnalyzer output, String option, boolean public static void testDefaultGC(boolean actAsServer) throws Exception { // Start VM without specifying GC - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeLimitedTestJava( "-XX:" + (actAsServer ? "+" : "-") + "AlwaysActAsServerClassMachine", "-XX:" + (actAsServer ? "-" : "+") + "NeverActAsServerClassMachine", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); final boolean isServer = actAsServer; diff --git a/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java b/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java index 779a5d8b537..f517e094edd 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java +++ b/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java @@ -60,14 +60,13 @@ public static void main(String[] args) throws Exception { long initHeap = heapAlignment; long maxHeap = heapAlignment * 2; - ProcessBuilder pb_enabled = GCArguments.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava( "-XX:+UseParallelGC", "-Xms" + String.valueOf(initHeap), "-Xmx" + String.valueOf(maxHeap), "-XX:+UseNUMA", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb_enabled.start()); if (largePageOrNumaEnabled(analyzer)) { // We reach here, if both NUMA and HugeTLB are supported. diff --git a/test/hotspot/jtreg/gc/arguments/TestSoftMaxHeapSizeFlag.java b/test/hotspot/jtreg/gc/arguments/TestSoftMaxHeapSizeFlag.java index a61e7545522..3d8f31db864 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSoftMaxHeapSizeFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestSoftMaxHeapSizeFlag.java @@ -42,36 +42,36 @@ public class TestSoftMaxHeapSizeFlag { public static void main(String args[]) throws Exception { // Test default value - ProcessTools.executeTestJvm("-Xms" + Xms, "-Xmx" + Xmx, - "-XX:+PrintFlagsFinal", "-version") + ProcessTools.executeTestJava("-Xms" + Xms, "-Xmx" + Xmx, + "-XX:+PrintFlagsFinal", "-version") .shouldMatch("SoftMaxHeapSize[ ]+=[ ]+" + Xmx) .shouldHaveExitValue(0); // Test setting small value - ProcessTools.executeTestJvm("-Xms" + Xms, "-Xmx" + Xmx, - "-XX:SoftMaxHeapSize=" + Xms, - "-XX:+PrintFlagsFinal", "-version") + ProcessTools.executeTestJava("-Xms" + Xms, "-Xmx" + Xmx, + "-XX:SoftMaxHeapSize=" + Xms, + "-XX:+PrintFlagsFinal", "-version") .shouldMatch("SoftMaxHeapSize[ ]+=[ ]+" + Xms) .shouldHaveExitValue(0); // Test setting middle value - ProcessTools.executeTestJvm("-Xms" + Xms, "-Xmx" + Xmx, - "-XX:SoftMaxHeapSize=" + betweenXmsAndXmx, - "-XX:+PrintFlagsFinal", "-version") + ProcessTools.executeTestJava("-Xms" + Xms, "-Xmx" + Xmx, + "-XX:SoftMaxHeapSize=" + betweenXmsAndXmx, + "-XX:+PrintFlagsFinal", "-version") .shouldMatch("SoftMaxHeapSize[ ]+=[ ]+" + betweenXmsAndXmx) .shouldHaveExitValue(0); // Test setting largest value - ProcessTools.executeTestJvm("-Xms" + Xms, "-Xmx" + Xmx, - "-XX:SoftMaxHeapSize=" + Xmx, - "-XX:+PrintFlagsFinal", "-version") + ProcessTools.executeTestJava("-Xms" + Xms, "-Xmx" + Xmx, + "-XX:SoftMaxHeapSize=" + Xmx, + "-XX:+PrintFlagsFinal", "-version") .shouldMatch("SoftMaxHeapSize[ ]+=[ ]+" + Xmx) .shouldHaveExitValue(0); // Test setting a too large value - ProcessTools.executeTestJvm("-Xms" + Xms, "-Xmx" + Xmx, - "-XX:SoftMaxHeapSize=" + greaterThanXmx, - "-XX:+PrintFlagsFinal", "-version") + ProcessTools.executeTestJava("-Xms" + Xms, "-Xmx" + Xmx, + "-XX:SoftMaxHeapSize=" + greaterThanXmx, + "-XX:+PrintFlagsFinal", "-version") .shouldContain("SoftMaxHeapSize must be less than or equal to the maximum heap size") .shouldHaveExitValue(1); } diff --git a/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java b/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java index 8567615220a..a593970e6f7 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java @@ -87,8 +87,7 @@ public static void testSurvivorRatio(int ratio, LinkedList options) thro Integer.toString(ratio) ); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/arguments/TestTargetSurvivorRatioFlag.java b/test/hotspot/jtreg/gc/arguments/TestTargetSurvivorRatioFlag.java index 8f8b4aa1087..afe424896b5 100644 --- a/test/hotspot/jtreg/gc/arguments/TestTargetSurvivorRatioFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestTargetSurvivorRatioFlag.java @@ -116,8 +116,7 @@ public static void negativeTest(int ratio, LinkedList options) throws Ex vmOptions.add("-XX:TargetSurvivorRatio=" + ratio); vmOptions.add("-version"); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(1); analyzer.shouldContain("Error: Could not create the Java Virtual Machine."); @@ -151,8 +150,7 @@ public static void positiveTest(int ratio, LinkedList options) throws Ex Integer.toString(ratio) ); - ProcessBuilder procBuilder = GCArguments.createLimitedTestJavaProcessBuilder(vmOptions); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); analyzer.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java b/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java index 24da380298b..f944c0c4e74 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java +++ b/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java @@ -40,32 +40,29 @@ public class TestUnrecognizedVMOptionsHandling { public static void main(String args[]) throws Exception { // The first two JAVA processes are expected to fail, but with a correct VM option suggestion - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder( + OutputAnalyzer outputWithError = GCArguments.executeLimitedTestJava( "-XX:+UseDynamicNumberOfGcThreads", "-version" ); - OutputAnalyzer outputWithError = new OutputAnalyzer(pb.start()); outputWithError.shouldContain("Did you mean '(+/-)UseDynamicNumberOfGCThreads'?"); if (outputWithError.getExitValue() == 0) { throw new RuntimeException("Not expected to get exit value 0"); } - pb = GCArguments.createLimitedTestJavaProcessBuilder( + outputWithError = GCArguments.executeLimitedTestJava( "-XX:MaxiumHeapSize=500m", "-version" ); - outputWithError = new OutputAnalyzer(pb.start()); outputWithError.shouldContain("Did you mean 'MaxHeapSize='?"); if (outputWithError.getExitValue() == 0) { throw new RuntimeException("Not expected to get exit value 0"); } // The last JAVA process should run successfully for the purpose of sanity check - pb = GCArguments.createLimitedTestJavaProcessBuilder( + OutputAnalyzer outputWithNoError = GCArguments.executeLimitedTestJava( "-XX:+UseDynamicNumberOfGCThreads", "-version" ); - OutputAnalyzer outputWithNoError = new OutputAnalyzer(pb.start()); outputWithNoError.shouldNotContain("Did you mean '(+/-)UseDynamicNumberOfGCThreads'?"); outputWithNoError.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java b/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java index 19ebdea3c0e..2a1d2fef879 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java +++ b/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java @@ -93,8 +93,7 @@ public static OutputAnalyzer runWhiteBoxTest(String[] vmargs, String classname, finalargs.add(classname); finalargs.addAll(Arrays.asList(arguments)); - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(finalargs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(finalargs); output.shouldHaveExitValue(0); return output; } @@ -157,8 +156,7 @@ private static boolean getFlagBoolValue(String flag, String where) { } private static String expect(String[] flags, boolean hasWarning, boolean hasError, int errorcode) throws Exception { - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(flags); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = GCArguments.executeLimitedTestJava(flags); output.shouldHaveExitValue(errorcode); return output.getStdout(); } diff --git a/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsFlagsWithUlimit.java b/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsFlagsWithUlimit.java index 07cf4126970..495b36407b1 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsFlagsWithUlimit.java +++ b/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsFlagsWithUlimit.java @@ -59,9 +59,8 @@ private static void checkFlag(long ulimit, long maxram, int maxrampercent, boole // Convert bytes to kbytes for ulimit -v var ulimit_prefix = "ulimit -v " + (ulimit / 1024); - String cmd = ProcessTools.getCommandLine(ProcessTools.createTestJavaProcessBuilder(args.toArray(String[]::new))); - ProcessBuilder pb = new ProcessBuilder("sh", "-c", ulimit_prefix + ";" + cmd); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + String cmd = ProcessTools.getCommandLine(ProcessTools.createTestJavaProcessBuilder(args)); + OutputAnalyzer output = ProcessTools.executeProcess("sh", "-c", ulimit_prefix + ";" + cmd); output.shouldHaveExitValue(0); String stdout = output.getStdout(); diff --git a/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java b/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java index 4a7fb7108c3..29c13f1fd90 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java +++ b/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java @@ -39,11 +39,10 @@ public class TestUseNUMAInterleaving { public static void main(String[] args) throws Exception { - ProcessBuilder pb = GCArguments.createTestJavaProcessBuilder( + OutputAnalyzer output = GCArguments.executeTestJava( "-XX:+UseNUMA", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); boolean isNUMAEnabled = Boolean.parseBoolean(output.firstMatch(NUMA_FLAG_PATTERN, 1)); diff --git a/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java b/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java index a3d6d5a7440..cc1f9be6fb7 100644 --- a/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java @@ -99,8 +99,7 @@ public static void testVerifyFlags(boolean verifyBeforeGC, : "-XX:-VerifyAfterGC"), GarbageProducer.class.getName(), doFullGC ? "t" : "f" }); - ProcessBuilder pb = GCArguments.createLimitedTestJavaProcessBuilder(vmOpts); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOpts); analyzer.shouldHaveExitValue(0); analyzer.shouldNotMatch(VERIFY_BEFORE_GC_CORRUPTED_PATTERN); diff --git a/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java b/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java index 238e747fb1e..9af3baf87b3 100644 --- a/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java +++ b/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java @@ -45,7 +45,7 @@ public class TestG1ClassUnloadingHWM { private static long YoungGenSize = 32 * 1024 * 1024; private static OutputAnalyzer run(boolean enableUnloading) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + return ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", @@ -57,7 +57,6 @@ private static OutputAnalyzer run(boolean enableUnloading) throws Exception { TestG1ClassUnloadingHWM.AllocateBeyondMetaspaceSize.class.getName(), "" + MetaspaceSize, "" + YoungGenSize); - return new OutputAnalyzer(pb.start()); } public static OutputAnalyzer runWithG1ClassUnloading() throws Exception { diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java b/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java index c978f149fca..016bb517c3c 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java @@ -37,15 +37,13 @@ public class TestDieDefault { public static void passWith(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); + OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); out.shouldNotContain("OutOfMemoryError"); out.shouldHaveExitValue(0); } public static void failWith(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); + OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); out.shouldContain("OutOfMemoryError"); if (out.getExitValue() == 0) { throw new IllegalStateException("Should have failed with non-zero exit code"); diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java b/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java index 2e19141d286..8f6e9a36d77 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java @@ -38,8 +38,7 @@ public class TestDieWithHeapDump { public static void passWith(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); + OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); out.shouldNotContain("OutOfMemoryError"); out.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java b/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java index a6593fecdff..7be60c59595 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java @@ -39,16 +39,14 @@ public class TestDieWithOnError { static String ON_ERR_MSG = "Epsilon error handler message"; public static void passWith(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); + OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); out.shouldNotContain("OutOfMemoryError"); out.stdoutShouldNotMatch("^" + ON_ERR_MSG); out.shouldHaveExitValue(0); } public static void failWith(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); + OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); out.shouldContain("OutOfMemoryError"); if (out.getExitValue() == 0) { throw new IllegalStateException("Should have failed with non-zero exit code"); diff --git a/test/hotspot/jtreg/gc/ergonomics/TestDynamicNumberOfGCThreads.java b/test/hotspot/jtreg/gc/ergonomics/TestDynamicNumberOfGCThreads.java index 288d27393a3..511f482980b 100644 --- a/test/hotspot/jtreg/gc/ergonomics/TestDynamicNumberOfGCThreads.java +++ b/test/hotspot/jtreg/gc/ergonomics/TestDynamicNumberOfGCThreads.java @@ -68,16 +68,16 @@ private static void testDynamicNumberOfGCThreads(String gcFlag) throws Exception String[] baseArgs = {"-XX:+UnlockExperimentalVMOptions", "-XX:+" + gcFlag, "-Xmx10M", "-XX:+UseDynamicNumberOfGCThreads", "-Xlog:gc+task=trace", GCTest.class.getName()}; // Base test with gc and +UseDynamicNumberOfGCThreads: - ProcessBuilder pb_enabled = ProcessTools.createLimitedTestJavaProcessBuilder(baseArgs); - verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start())); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(baseArgs); + verifyDynamicNumberOfGCThreads(output); // Turn on parallel reference processing String[] parRefProcArg = {"-XX:+ParallelRefProcEnabled", "-XX:-ShowMessageBoxOnError"}; String[] parRefArgs = new String[baseArgs.length + parRefProcArg.length]; System.arraycopy(parRefProcArg, 0, parRefArgs, 0, parRefProcArg.length); System.arraycopy(baseArgs, 0, parRefArgs, parRefProcArg.length, baseArgs.length); - pb_enabled = ProcessTools.createLimitedTestJavaProcessBuilder(parRefArgs); - verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start())); + output = ProcessTools.executeLimitedTestJava(parRefArgs); + verifyDynamicNumberOfGCThreads(output); } static class GCTest { diff --git a/test/hotspot/jtreg/gc/ergonomics/TestInitialGCThreadLogging.java b/test/hotspot/jtreg/gc/ergonomics/TestInitialGCThreadLogging.java index dc1b83cd2c1..e58b930b519 100644 --- a/test/hotspot/jtreg/gc/ergonomics/TestInitialGCThreadLogging.java +++ b/test/hotspot/jtreg/gc/ergonomics/TestInitialGCThreadLogging.java @@ -70,13 +70,13 @@ private static void verifyDynamicNumberOfGCThreads(OutputAnalyzer output, String private static void testInitialGCThreadLogging(String gcFlag, String threadName) throws Exception { // Base test with gc and +UseDynamicNumberOfGCThreads: - ProcessBuilder pb_enabled = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:+UnlockExperimentalVMOptions", "-XX:+" + gcFlag, "-Xmx10M", "-XX:+UseDynamicNumberOfGCThreads", "-Xlog:gc+task=trace", "-version"); - verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start()), threadName); + verifyDynamicNumberOfGCThreads(output, threadName); } } diff --git a/test/hotspot/jtreg/gc/g1/Test2GbHeap.java b/test/hotspot/jtreg/gc/g1/Test2GbHeap.java index 8e06ac3ee2c..9b981883714 100644 --- a/test/hotspot/jtreg/gc/g1/Test2GbHeap.java +++ b/test/hotspot/jtreg/gc/g1/Test2GbHeap.java @@ -49,9 +49,8 @@ public static void main(String[] args) throws Exception { testArguments.add("-Xmx2g"); testArguments.add("-version"); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(testArguments); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(testArguments); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java b/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java index 0723eb89f51..ab5e9d1b060 100644 --- a/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java +++ b/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java @@ -43,17 +43,16 @@ public class TestAllocationFailure { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx32M", - "-Xmn16M", - "-XX:+G1GCAllocationFailureALot", - "-XX:G1GCAllocationFailureALotCount=100", - "-XX:G1GCAllocationFailureALotInterval=1", - "-XX:+UnlockDiagnosticVMOptions", - "-Xlog:gc", - GCTestWithAllocationFailure.class.getName()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx32M", + "-Xmn16M", + "-XX:+G1GCAllocationFailureALot", + "-XX:G1GCAllocationFailureALotCount=100", + "-XX:G1GCAllocationFailureALotInterval=1", + "-XX:+UnlockDiagnosticVMOptions", + "-Xlog:gc", + GCTestWithAllocationFailure.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println(output.getStdout()); output.shouldContain("(Evacuation Failure:"); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegions.java b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegions.java index a334783eca6..d1ae8ab734c 100644 --- a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegions.java +++ b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegions.java @@ -80,7 +80,7 @@ public static void main(String[] args) { public class TestEagerReclaimHumongousRegions { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:+UseG1GC", "-Xms128M", "-Xmx128M", @@ -90,8 +90,6 @@ public static void main(String[] args) throws Exception { Pattern p = Pattern.compile("Full GC"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - int found = 0; Matcher m = p.matcher(output.getStdout()); while (m.find()) { found++; } diff --git a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java index 56de136fe59..4e4f864d339 100644 --- a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java +++ b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java @@ -119,7 +119,7 @@ public static void main(String[] args) { public class TestEagerReclaimHumongousRegionsClearMarkBits { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:+UseG1GC", "-Xms128M", "-Xmx128M", @@ -132,7 +132,6 @@ public static void main(String[] args) throws Exception { "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. "-XX:+G1VerifyBitmaps", TestEagerReclaimHumongousRegionsClearMarkBitsReclaimRegionFast.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsLog.java b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsLog.java index 03af9c2b4bb..33825bff0b7 100644 --- a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsLog.java +++ b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsLog.java @@ -54,7 +54,7 @@ private static String getSumValue(String s) { } public static void runTest() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", @@ -65,7 +65,6 @@ public static void runTest() throws Exception { "-Xmx128M", "-Xlog:gc+phases=trace,gc+heap=info", GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java index 335567a9c36..a555977eb3e 100644 --- a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java +++ b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java @@ -92,7 +92,7 @@ public static void main(String[] args) { public class TestEagerReclaimHumongousRegionsWithRefs { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:+UseG1GC", "-Xms128M", "-Xmx128M", @@ -102,8 +102,6 @@ public static void main(String[] args) throws Exception { Pattern p = Pattern.compile("Full GC"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - int found = 0; Matcher m = p.matcher(output.getStdout()); while (m.find()) { diff --git a/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java b/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java index 8455e03b18f..3e986a5dede 100644 --- a/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java +++ b/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java @@ -54,8 +54,7 @@ public static void runTest() throws Exception { "-XX:G1HeapRegionSize=1m", GCTest.class.getName() }; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(arguments); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(arguments); System.out.println(output.getStdout()); String pattern = ".*skip compaction region.*"; diff --git a/test/hotspot/jtreg/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java b/test/hotspot/jtreg/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java index 4dedac0a61b..d1cb29b314e 100644 --- a/test/hotspot/jtreg/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java +++ b/test/hotspot/jtreg/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java @@ -41,16 +41,14 @@ public class TestG1TraceEagerReclaimHumongousObjects { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xms128M", - "-Xmx128M", - "-Xmn16M", - "-XX:G1HeapRegionSize=1M", - "-Xlog:gc+phases=trace,gc+humongous=trace", - "-XX:+UnlockExperimentalVMOptions", - GCWithHumongousObjectTest.class.getName()); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn16M", + "-XX:G1HeapRegionSize=1M", + "-Xlog:gc+phases=trace,gc+humongous=trace", + "-XX:+UnlockExperimentalVMOptions", + GCWithHumongousObjectTest.class.getName()); System.out.println(output.getStdout()); // As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed. diff --git a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java index c29919e8aff..e5db6cb0dae 100644 --- a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java +++ b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java @@ -218,28 +218,25 @@ public static void main(String[] args) throws Exception { private void testNormalLogs() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - GCTest.class.getName()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx10M", + GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); checkMessagesAtLevel(output, allLogMessages, Level.OFF); output.shouldHaveExitValue(0); - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xlog:gc+phases=debug", - GCTest.class.getName()); + output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx10M", + "-Xlog:gc+phases=debug", + GCTest.class.getName()); - output = new OutputAnalyzer(pb.start()); checkMessagesAtLevel(output, allLogMessages, Level.DEBUG); - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xlog:gc+phases=trace", - GCTest.class.getName()); + output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx10M", + "-Xlog:gc+phases=trace", + GCTest.class.getName()); - output = new OutputAnalyzer(pb.start()); checkMessagesAtLevel(output, allLogMessages, Level.TRACE); output.shouldHaveExitValue(0); } @@ -253,11 +250,10 @@ private void testNormalLogs() throws Exception { }; private void testConcurrentRefinementLogs() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xlog:gc+refine+stats=debug", - GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx10M", + "-Xlog:gc+refine+stats=debug", + GCTest.class.getName()); checkMessagesAtLevel(output, concRefineMessages, Level.DEBUG); } @@ -272,29 +268,27 @@ private void testConcurrentRefinementLogs() throws Exception { }; private void testWithEvacuationFailureLogs() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx32M", - "-Xmn16M", - "-XX:+G1GCAllocationFailureALot", - "-XX:G1GCAllocationFailureALotCount=100", - "-XX:G1GCAllocationFailureALotInterval=1", - "-XX:+UnlockDiagnosticVMOptions", - "-Xlog:gc+phases=debug", - GCTestWithAllocationFailure.class.getName()); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx32M", + "-Xmn16M", + "-XX:+G1GCAllocationFailureALot", + "-XX:G1GCAllocationFailureALotCount=100", + "-XX:G1GCAllocationFailureALotInterval=1", + "-XX:+UnlockDiagnosticVMOptions", + "-Xlog:gc+phases=debug", + GCTestWithAllocationFailure.class.getName()); + checkMessagesAtLevel(output, exhFailureMessages, Level.DEBUG); output.shouldHaveExitValue(0); - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx32M", - "-Xmn16M", - "-Xms32M", - "-XX:+UnlockDiagnosticVMOptions", - "-Xlog:gc+phases=trace", - GCTestWithAllocationFailure.class.getName()); + output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx32M", + "-Xmn16M", + "-Xms32M", + "-XX:+UnlockDiagnosticVMOptions", + "-Xlog:gc+phases=trace", + GCTestWithAllocationFailure.class.getName()); - output = new OutputAnalyzer(pb.start()); checkMessagesAtLevel(output, exhFailureMessages, Level.TRACE); output.shouldHaveExitValue(0); } @@ -305,29 +299,27 @@ private void testWithEvacuationFailureLogs() throws Exception { }; private void testWithConcurrentStart() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xbootclasspath/a:.", - "-Xlog:gc*=debug", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - GCTestWithConcurrentStart.class.getName()); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx10M", + "-Xbootclasspath/a:.", + "-Xlog:gc*=debug", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + GCTestWithConcurrentStart.class.getName()); + checkMessagesAtLevel(output, concurrentStartMessages, Level.TRACE); output.shouldHaveExitValue(0); } private void testExpandHeap() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xbootclasspath/a:.", - "-Xlog:gc+ergo+heap=debug", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - GCTest.class.getName()); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-Xmx10M", + "-Xbootclasspath/a:.", + "-Xlog:gc+ergo+heap=debug", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + GCTest.class.getName()); + output.shouldContain("Expand the heap. requested expansion amount: "); output.shouldContain("B expansion amount: "); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.java b/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.java index b3a754f74c5..9631fd1855c 100644 --- a/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.java +++ b/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.java @@ -45,7 +45,7 @@ public class TestHumongousAllocConcurrentStart { private static final int initiatingHeapOccupancyPercent = 50; // % public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeTestJava( "-XX:+UseG1GC", "-Xms" + heapSize + "m", "-Xmx" + heapSize + "m", @@ -54,7 +54,6 @@ public static void main(String[] args) throws Exception { "-Xlog:gc", HumongousObjectAllocator.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Pause Young (Concurrent Start) (G1 Humongous Allocation)"); output.shouldNotContain("Full GC"); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java b/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java index fb33e9cc7c5..d6d8b5578cc 100644 --- a/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java +++ b/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java @@ -47,7 +47,7 @@ public class TestHumongousAllocNearlyFullRegion { private static final int heapRegionSize = 1; // MB public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:+UseG1GC", "-Xms" + heapSize + "m", "-Xmx" + heapSize + "m", @@ -55,7 +55,6 @@ public static void main(String[] args) throws Exception { "-Xlog:gc", HumongousObjectAllocator.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Pause Young (Concurrent Start) (G1 Humongous Allocation)"); output.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java b/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java index 2e669f6dfe1..97ffd6c8da7 100644 --- a/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java +++ b/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java @@ -106,8 +106,7 @@ public static OutputAnalyzer runWhiteBoxTest(String[] vmargs, String classname, finalargs.add(classname); finalargs.addAll(Arrays.asList(arguments)); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(finalargs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(finalargs); output.shouldHaveExitValue(0); return output; } diff --git a/test/hotspot/jtreg/gc/g1/TestHumongousConcurrentStartUndo.java b/test/hotspot/jtreg/gc/g1/TestHumongousConcurrentStartUndo.java index d30d9240103..ed5ff35021a 100644 --- a/test/hotspot/jtreg/gc/g1/TestHumongousConcurrentStartUndo.java +++ b/test/hotspot/jtreg/gc/g1/TestHumongousConcurrentStartUndo.java @@ -56,7 +56,7 @@ public class TestHumongousConcurrentStartUndo { private static final int YoungSize = HeapSize / 8; public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-XX:+UseG1GC", "-Xms" + HeapSize + "m", @@ -70,7 +70,6 @@ public static void main(String[] args) throws Exception { "-Xlog:gc*", EdenObjectAllocatorWithHumongousAllocation.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Pause Young (Concurrent Start) (G1 Humongous Allocation)"); output.shouldContain("Concurrent Undo Cycle"); output.shouldContain("Concurrent Mark Cycle"); diff --git a/test/hotspot/jtreg/gc/g1/TestLargePageUseForAuxMemory.java b/test/hotspot/jtreg/gc/g1/TestLargePageUseForAuxMemory.java index 777391845a4..3051cd7310b 100644 --- a/test/hotspot/jtreg/gc/g1/TestLargePageUseForAuxMemory.java +++ b/test/hotspot/jtreg/gc/g1/TestLargePageUseForAuxMemory.java @@ -120,12 +120,9 @@ static List getOpts(long heapsize, boolean largePageEnabled) { static void testVM(String what, long heapsize, boolean cardsShouldUseLargePages, boolean bitmapShouldUseLargePages) throws Exception { System.out.println(what + " heapsize " + heapsize + " card table should use large pages " + cardsShouldUseLargePages + " " + "bitmaps should use large pages " + bitmapShouldUseLargePages); - ProcessBuilder pb; // Test with large page enabled. - pb = ProcessTools.createLimitedTestJavaProcessBuilder(getOpts(heapsize, true)); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(getOpts(heapsize, true)); // Only expect large page size if large pages are enabled. if (largePagesEnabled(output)) { @@ -138,9 +135,8 @@ static void testVM(String what, long heapsize, boolean cardsShouldUseLargePages, output.shouldHaveExitValue(0); // Test with large page disabled. - pb = ProcessTools.createLimitedTestJavaProcessBuilder(getOpts(heapsize, false)); + output = ProcessTools.executeLimitedTestJava(getOpts(heapsize, false)); - output = new OutputAnalyzer(pb.start()); checkSmallTables(output, smallPageSize); checkBitmap(output, smallPageSize); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestLargePageUseForHeap.java b/test/hotspot/jtreg/gc/g1/TestLargePageUseForHeap.java index 72afde512bc..7009ae00d92 100644 --- a/test/hotspot/jtreg/gc/g1/TestLargePageUseForHeap.java +++ b/test/hotspot/jtreg/gc/g1/TestLargePageUseForHeap.java @@ -85,29 +85,26 @@ static void checkHeap(OutputAnalyzer output, long expectedPageSize) throws Excep } static void testVM(long regionSize) throws Exception { - ProcessBuilder pb; // Test with large page enabled. - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:G1HeapRegionSize=" + regionSize, - "-Xmx128m", - "-Xlog:gc+init,pagesize,gc+heap+coops=debug", - "-XX:+UseLargePages", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + regionSize, + "-Xmx128m", + "-Xlog:gc+init,pagesize,gc+heap+coops=debug", + "-XX:+UseLargePages", + "-version"); + boolean largePageEnabled = checkLargePageEnabled(output); checkHeap(output, largePageEnabled ? largePageSize : smallPageSize); output.shouldHaveExitValue(0); // Test with large page disabled. - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:G1HeapRegionSize=" + regionSize, - "-Xmx128m", - "-Xlog:gc+init,pagesize,gc+heap+coops=debug", - "-XX:-UseLargePages", - "-version"); - - output = new OutputAnalyzer(pb.start()); + output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + regionSize, + "-Xmx128m", + "-Xlog:gc+init,pagesize,gc+heap+coops=debug", + "-XX:-UseLargePages", + "-version"); + checkHeap(output, smallPageSize); output.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/g1/TestMarkStackOverflow.java b/test/hotspot/jtreg/gc/g1/TestMarkStackOverflow.java new file mode 100644 index 00000000000..754d811e664 --- /dev/null +++ b/test/hotspot/jtreg/gc/g1/TestMarkStackOverflow.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc.g1; + +import java.util.LinkedHashMap; + +/* @test + * @bug 8313212 + * @summary Finalizing objects may create new concurrent marking work during reference processing. + * If the marking work overflows the global mark stack, we should resize the global mark stack + * until MarkStackSizeMax if possible. + * @requires vm.gc.G1 + * @run main/othervm -XX:ActiveProcessorCount=2 -XX:MarkStackSize=1 -Xmx250m gc.g1.TestMarkStackOverflow + */ + +public class TestMarkStackOverflow { + public static void main(String[] args) throws Exception { + for (int i = 0; i < 10; i++) { + Finalizable holder1 = new Finalizable(); + System.out.printf("Used mem %.2f MB\n", getUsedMem()); + } + } + + private static double getUsedMem() { + return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (double) (1024 * 1024); + } + + private static class Finalizable { + public static final int NUM_OBJECTS = 200_000; + private final LinkedHashMap list = new LinkedHashMap<>(); + + public Finalizable() { + for (int i = 0; i < NUM_OBJECTS; i++) { + Object entry = new Object(); + list.put(entry, entry); + } + } + + @SuppressWarnings("removal") + protected void finalize() { + System.out.print(""); + } + } +} diff --git a/test/hotspot/jtreg/gc/g1/TestMarkStackSizes.java b/test/hotspot/jtreg/gc/g1/TestMarkStackSizes.java index d056a5ef747..0a1c373199c 100644 --- a/test/hotspot/jtreg/gc/g1/TestMarkStackSizes.java +++ b/test/hotspot/jtreg/gc/g1/TestMarkStackSizes.java @@ -50,9 +50,7 @@ private static void runTest(boolean shouldSucceed, String... extraArgs) throws E Collections.addAll(testArguments, extraArgs); testArguments.add("-version"); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(testArguments); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(testArguments); System.out.println(output.getStderr()); diff --git a/test/hotspot/jtreg/gc/g1/TestMixedGCLiveThreshold.java b/test/hotspot/jtreg/gc/g1/TestMixedGCLiveThreshold.java index 035a6b89679..e0aa0827749 100644 --- a/test/hotspot/jtreg/gc/g1/TestMixedGCLiveThreshold.java +++ b/test/hotspot/jtreg/gc/g1/TestMixedGCLiveThreshold.java @@ -109,9 +109,7 @@ private static OutputAnalyzer testWithMixedGCLiveThresholdPercent(int percent) t basicOpts.add(GCTest.class.getName()); - ProcessBuilder procBuilder = ProcessTools.createLimitedTestJavaProcessBuilder(basicOpts); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); - return analyzer; + return ProcessTools.executeLimitedTestJava(basicOpts); } private static boolean regionsSelectedForRebuild(String output) throws Exception { diff --git a/test/hotspot/jtreg/gc/g1/TestOneEdenRegionAfterGC.java b/test/hotspot/jtreg/gc/g1/TestOneEdenRegionAfterGC.java index 36c3c04c629..6bbf0213f36 100644 --- a/test/hotspot/jtreg/gc/g1/TestOneEdenRegionAfterGC.java +++ b/test/hotspot/jtreg/gc/g1/TestOneEdenRegionAfterGC.java @@ -40,7 +40,7 @@ public class TestOneEdenRegionAfterGC { private static long YoungGenSize = 32 * 1024 * 1024; private static OutputAnalyzer run() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + return ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-Xmn" + YoungGenSize, "-Xmx512M", @@ -50,7 +50,6 @@ private static OutputAnalyzer run() throws Exception { "-Xlog:gc,gc+ergo*=trace", TestOneEdenRegionAfterGC.Allocate.class.getName(), "" + YoungGenSize); - return new OutputAnalyzer(pb.start()); } public static void main(String args[]) throws Exception { diff --git a/test/hotspot/jtreg/gc/g1/TestPLABOutput.java b/test/hotspot/jtreg/gc/g1/TestPLABOutput.java index e6342a1911c..fecb8dcfc41 100644 --- a/test/hotspot/jtreg/gc/g1/TestPLABOutput.java +++ b/test/hotspot/jtreg/gc/g1/TestPLABOutput.java @@ -59,8 +59,7 @@ public static void runTest() throws Exception { GCTest.class.getName() }; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(arguments); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(arguments); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestPLABSizeBounds.java b/test/hotspot/jtreg/gc/g1/TestPLABSizeBounds.java index ade281a4a92..c0427e1ada3 100644 --- a/test/hotspot/jtreg/gc/g1/TestPLABSizeBounds.java +++ b/test/hotspot/jtreg/gc/g1/TestPLABSizeBounds.java @@ -62,8 +62,7 @@ public static void runTest(int regionSize, int plabSize, boolean shouldSucceed) testArguments.add("-XX:OldPLABSize=" + plabSize); testArguments.add(GCTest.class.getName()); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(testArguments); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(testArguments); if (shouldSucceed) { output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java b/test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java index de79be020b4..7b4303e55a2 100644 --- a/test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java +++ b/test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java @@ -40,24 +40,22 @@ public class TestPeriodicLogMessages { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:G1PeriodicGCInterval=0", - "-Xlog:gc+init,gc+periodic=debug", - "-Xmx10M", - GCTest.class.getName()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:G1PeriodicGCInterval=0", + "-Xlog:gc+init,gc+periodic=debug", + "-Xmx10M", + GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Periodic GC: Disabled"); output.shouldNotContain("Checking for periodic GC"); output.shouldHaveExitValue(0); - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:G1PeriodicGCInterval=100", - "-Xlog:gc+init,gc+periodic=debug", - "-Xmx10M", - GCTest.class.getName()); + output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:G1PeriodicGCInterval=100", + "-Xlog:gc+init,gc+periodic=debug", + "-Xmx10M", + GCTest.class.getName()); - output = new OutputAnalyzer(pb.start()); output.shouldContain("Periodic GC: Enabled"); output.shouldContain("Periodic GC Interval: 100ms"); output.shouldContain("Checking for periodic GC"); diff --git a/test/hotspot/jtreg/gc/g1/TestPrintRegionRememberedSetInfo.java b/test/hotspot/jtreg/gc/g1/TestPrintRegionRememberedSetInfo.java index ea718c7f6ed..11f02643d1d 100644 --- a/test/hotspot/jtreg/gc/g1/TestPrintRegionRememberedSetInfo.java +++ b/test/hotspot/jtreg/gc/g1/TestPrintRegionRememberedSetInfo.java @@ -69,8 +69,7 @@ public static String runTest(String arg) throws Exception { finalargs.add(RunAndWaitForMarking.class.getName()); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(finalargs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(finalargs); output.shouldHaveExitValue(0); String result = output.getStdout(); diff --git a/test/hotspot/jtreg/gc/g1/TestRemsetLoggingThreads.java b/test/hotspot/jtreg/gc/g1/TestRemsetLoggingThreads.java index 5d4b4d958f8..c2b1be60322 100644 --- a/test/hotspot/jtreg/gc/g1/TestRemsetLoggingThreads.java +++ b/test/hotspot/jtreg/gc/g1/TestRemsetLoggingThreads.java @@ -44,14 +44,12 @@ public class TestRemsetLoggingThreads { private static void runTest(int refinementThreads, int workerThreads) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+UnlockDiagnosticVMOptions", - "-Xlog:gc+remset+exit=trace", - "-XX:G1ConcRefinementThreads=" + refinementThreads, - "-XX:ParallelGCThreads=" + workerThreads, - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-Xlog:gc+remset+exit=trace", + "-XX:G1ConcRefinementThreads=" + refinementThreads, + "-XX:ParallelGCThreads=" + workerThreads, + "-version"); String pattern = "Concurrent refinement threads times \\(s\\)$"; Matcher m = Pattern.compile(pattern, Pattern.MULTILINE).matcher(output.getStdout()); diff --git a/test/hotspot/jtreg/gc/g1/TestRemsetLoggingTools.java b/test/hotspot/jtreg/gc/g1/TestRemsetLoggingTools.java index 69f34e07146..7e44c41e1a4 100644 --- a/test/hotspot/jtreg/gc/g1/TestRemsetLoggingTools.java +++ b/test/hotspot/jtreg/gc/g1/TestRemsetLoggingTools.java @@ -77,8 +77,7 @@ public static String runTest(String[] additionalArgs, int numGCs) throws Excepti finalargs.add(VerifySummaryOutput.class.getName()); finalargs.add(String.valueOf(numGCs)); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(finalargs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(finalargs); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java b/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java index d894c58d737..aef9a98530c 100644 --- a/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java +++ b/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java @@ -50,8 +50,6 @@ public static void main(String[] args) throws Exception { final List BaseOptions = Arrays.asList(new String[] {"-XX:+UseG1GC", "-XX:+AlwaysPreTouch", "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + ArchiveFileName }); - ProcessBuilder pb; - List dump_args = new ArrayList(BaseOptions); if (Platform.is64bit()) { @@ -59,8 +57,8 @@ public static void main(String[] args) throws Exception { } dump_args.addAll(Arrays.asList(new String[] { "-Xshare:dump", "-Xlog:cds" })); - pb = ProcessTools.createLimitedTestJavaProcessBuilder(dump_args); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(dump_args); + try { output.shouldContain("Loading classes to share"); output.shouldHaveExitValue(0); @@ -72,8 +70,7 @@ public static void main(String[] args) throws Exception { } load_args.addAll(Arrays.asList(new String[] { "-Xshare:on", "-version" })); - pb = ProcessTools.createLimitedTestJavaProcessBuilder(load_args.toArray(new String[0])); - output = new OutputAnalyzer(pb.start()); + output = ProcessTools.executeLimitedTestJava(load_args.toArray(new String[0])); output.shouldContain("sharing"); output.shouldHaveExitValue(0); } catch (RuntimeException e) { diff --git a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java index 645e545443d..8f68ccba9ad 100644 --- a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java +++ b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java @@ -88,9 +88,8 @@ protected void test() throws Exception { } private void performTest(List opts) throws Exception { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(opts); + OutputAnalyzer output = ProcessTools.executeTestJava(opts); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println(output.getStdout()); System.err.println(output.getStderr()); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/g1/TestShrinkDefragmentedHeap.java b/test/hotspot/jtreg/gc/g1/TestShrinkDefragmentedHeap.java index acdce6b6417..7934660a323 100644 --- a/test/hotspot/jtreg/gc/g1/TestShrinkDefragmentedHeap.java +++ b/test/hotspot/jtreg/gc/g1/TestShrinkDefragmentedHeap.java @@ -61,7 +61,7 @@ public class TestShrinkDefragmentedHeap { private static final int REGION_SIZE = 1 * 1024 * 1024; public static void main(String[] args) throws Exception, Throwable { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE, "-Xmn" + MINIMAL_YOUNG_SIZE, "-Xmx" + MAXIMUM_HEAP_SIZE, @@ -74,7 +74,6 @@ public static void main(String[] args) throws Exception, Throwable { GCTest.class.getName() ); - OutputAnalyzer output = ProcessTools.executeProcess(pb); output.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java index 4c7190ada02..1dc64bf6255 100644 --- a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java +++ b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java @@ -40,17 +40,16 @@ public class TestSkipRebuildRemsetPhase { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xbootclasspath/a:.", - "-XX:+UseG1GC", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-XX:G1MixedGCLiveThresholdPercent=20", - "-Xlog:gc+marking=debug,gc+phases=debug,gc+remset+tracking=trace", - "-Xms10M", - "-Xmx10M", - GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-Xbootclasspath/a:.", + "-XX:+UseG1GC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:G1MixedGCLiveThresholdPercent=0", + "-Xlog:gc+marking=debug,gc+phases=debug,gc+remset+tracking=trace", + "-Xms10M", + "-Xmx10M", + GCTest.class.getName()); output.shouldContain("Skipping Remembered Set Rebuild."); output.shouldContain("No Remembered Sets to update after rebuild"); output.shouldHaveExitValue(0); @@ -59,24 +58,20 @@ public static void main(String[] args) throws Exception { public static class GCTest { public static void main(String args[]) throws Exception { WhiteBox wb = WhiteBox.getWhiteBox(); - // Allocate some memory less than region size. - Object used = alloc(); + // Allocate some memory less than region size. Any object is just fine as we set + // G1MixedGCLiveThresholdPercent to zero (and no region should be selected). + Object used = new byte[2000]; - // Trigger the full GC using the WhiteBox API. - wb.fullGC(); // full + // Trigger the full GC using the WhiteBox API to make sure that at least "used" + // has been promoted to old gen. + wb.fullGC(); // Memory objects have been promoted to old by full GC. - // Concurrent cycle should not select any regions for rebuilding + // Concurrent cycle should not select any regions for rebuilding and print the + // appropriate message. wb.g1RunConcurrentGC(); System.out.println(used); } - - private static Object alloc() { - // Since G1MixedGCLiveThresholdPercent is 20%, make sure to allocate object larger than that - // so that it will not be collected and the expected message printed. - final int objectSize = WhiteBox.getWhiteBox().g1RegionSize() / 3; - Object ret = new byte[objectSize]; - return ret; - } } } + diff --git a/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java b/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java index d14fcf95de1..2f3b3128038 100644 --- a/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java +++ b/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java @@ -178,10 +178,7 @@ private static OutputAnalyzer testWithVerificationType(String[] types, String... basicOpts.add(TriggerGCs.class.getName()); - ProcessBuilder procBuilder = ProcessTools.createLimitedTestJavaProcessBuilder(basicOpts); - OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); - - return analyzer; + return ProcessTools.executeLimitedTestJava(basicOpts); } private static void verifyCollection(String name, boolean expectBefore, boolean expectDuring, boolean expectAfter, String data) { diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/ClassLoaderGenerator.java b/test/hotspot/jtreg/gc/g1/humongousObjects/ClassLoaderGenerator.java index 25510063b55..01ad5e1c0b3 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/ClassLoaderGenerator.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/ClassLoaderGenerator.java @@ -34,7 +34,7 @@ * Since the generation depends on current host architecture it cannot be done as part of pre-compilation step */ public class ClassLoaderGenerator { - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { if (args.length != 1) { throw new Error("Test Bug: Expected region size wasn't provided as command line argument"); @@ -47,7 +47,7 @@ public static void main(String[] args) throws IOException { } - public static void generateClassLoader(long regionSize, Path wrkDir) throws IOException { + public static void generateClassLoader(long regionSize, Path wrkDir) throws Exception { // Generating simple classloader String finalSimpleClassLoaderPrototype = TestHumongousClassLoader.GENERIC_PROTOTYPE .replace("${Methods}", diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/G1SampleClass.java b/test/hotspot/jtreg/gc/g1/humongousObjects/G1SampleClass.java index 1a321c9b115..8e11eff2749 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/G1SampleClass.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/G1SampleClass.java @@ -75,12 +75,11 @@ public long expectedInstanceSize() { * @param wrkDir working dir where generated classes are put and compiled * @param classNamePrefix prefix for service classes (ones we use to create chain of inheritance) * @return a class with instances of the specified size loaded in specified class loader - * @throws IOException - * @throws ClassNotFoundException + * @throws Exception */ public Class getCls(ClassLoader classLoader, Path wrkDir, String classNamePrefix) - throws IOException, ClassNotFoundException { + throws Exception { return Helpers.generateCompileAndLoad(classLoader, Helpers.enumNameToClassName(name()) + "Class", expectedInstanceSize(), wrkDir, classNamePrefix); } diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java index c2be830f57c..34333e90ef2 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java @@ -140,9 +140,7 @@ public void provoke() { public abstract void provoke(); } - public static void main(String[] args) throws ClassNotFoundException, InstantiationException, - IllegalAccessException, IOException, NoSuchMethodException, InvocationTargetException { - + public static void main(String[] args) throws Exception { if (args.length != 1) { throw new Error("Test Bug: Expected GC type wasn't provided as command line argument"); } diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java index 32a4251a6a8..0e432177208 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java @@ -82,8 +82,7 @@ public class TestHumongousNonArrayAllocation { private static final WhiteBox WB = WhiteBox.getWhiteBox(); private static final String CLASS_NAME_PREFIX = TestHumongousNonArrayAllocation.class.getSimpleName() + "_"; - public static void main(String[] args) throws ClassNotFoundException, InstantiationException, - IllegalAccessException, IOException { + public static void main(String[] args) throws Exception { if (args.length != 1) { throw new Error("Test Bug: Expected class name wasn't provided as command line argument"); diff --git a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java index a93232dd82e..a962efba460 100644 --- a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java +++ b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java @@ -129,7 +129,7 @@ private static void runTest(int heapSize, int sleepTime, boolean isIhopAdaptive) } private static OutputAnalyzer executeTest(List options) throws Throwable, RuntimeException { - OutputAnalyzer out = ProcessTools.executeTestJvm(options); + OutputAnalyzer out = ProcessTools.executeTestJava(options); if (out.getExitValue() != 0) { System.out.println(out.getOutput()); throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue()); diff --git a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPStatic.java b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPStatic.java index c84374fa359..7f5259a0855 100644 --- a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPStatic.java +++ b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPStatic.java @@ -129,7 +129,7 @@ private static void runTest(int ihop, long pctToFill, long heapSize, boolean exp Collections.addAll(options, COMMON_OPTIONS); options.add(AppIHOP.class.getName()); - OutputAnalyzer out = ProcessTools.executeTestJvm(options); + OutputAnalyzer out = ProcessTools.executeTestJava(options); if (out.getExitValue() != 0) { System.out.println(out.getOutput()); diff --git a/test/hotspot/jtreg/gc/g1/logging/TestG1LoggingFailure.java b/test/hotspot/jtreg/gc/g1/logging/TestG1LoggingFailure.java index befa34dea65..eb008f04e52 100644 --- a/test/hotspot/jtreg/gc/g1/logging/TestG1LoggingFailure.java +++ b/test/hotspot/jtreg/gc/g1/logging/TestG1LoggingFailure.java @@ -63,7 +63,7 @@ public static void main(String[] args) throws Throwable { } private static void startVM(List options) throws Throwable, RuntimeException { - OutputAnalyzer out = ProcessTools.executeTestJvm(options); + OutputAnalyzer out = ProcessTools.executeTestJava(options); out.shouldNotContain("pure virtual method called"); diff --git a/test/hotspot/jtreg/gc/g1/mixedgc/TestLogging.java b/test/hotspot/jtreg/gc/g1/mixedgc/TestLogging.java index 0c8d4896c4e..0e8f2b47762 100644 --- a/test/hotspot/jtreg/gc/g1/mixedgc/TestLogging.java +++ b/test/hotspot/jtreg/gc/g1/mixedgc/TestLogging.java @@ -90,8 +90,7 @@ private static OutputAnalyzer spawnMixedGCProvoker(String... extraFlags) Collections.addAll(testOpts, extraFlags); testOpts.add(RunMixedGC.class.getName()); System.out.println(testOpts); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(testOpts); - return new OutputAnalyzer(pb.start()); + return ProcessTools.executeLimitedTestJava(testOpts); } } diff --git a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java index 4f972e10f31..832281c8257 100644 --- a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java +++ b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java @@ -181,7 +181,7 @@ static void testMemoryTouch(String largePagesSetting, int regionSizeInMB) throws return; } - ProcessBuilder pb_enabled = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xbootclasspath/a:.", "-Xlog:pagesize,gc+heap+region=trace", "-XX:+UseG1GC", @@ -195,7 +195,6 @@ static void testMemoryTouch(String largePagesSetting, int regionSizeInMB) throws largePagesSetting, "-XX:G1HeapRegionSize=" + regionSizeInMB + "m", GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); // Check NUMA availability. if (status == NUMASupportStatus.NOT_CHECKED) { diff --git a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectTypes.java b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectTypes.java index ff730a30106..c96f1a1759a 100644 --- a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectTypes.java +++ b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectTypes.java @@ -48,17 +48,17 @@ public static void main(String[] args) throws Exception { } private static void testPinning(String type, boolean shouldSucceed) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-Xbootclasspath/a:.", - "-Xmx32M", - "-Xmn16M", - "-Xlog:gc", - TestObjectPin.class.getName(), - type); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:.", + "-XX:-CreateCoredumpOnCrash", + "-Xmx32M", + "-Xmn16M", + "-Xlog:gc", + TestObjectPin.class.getName(), + type); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println(output.getStdout()); if (shouldSucceed) { output.shouldHaveExitValue(0); @@ -83,4 +83,3 @@ public static void main(String[] args) { wb.pinObject(o); } } - diff --git a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectsEvacuation.java b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectsEvacuation.java index 7ffd9432eb5..975b1feb536 100644 --- a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectsEvacuation.java +++ b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectsEvacuation.java @@ -64,19 +64,18 @@ private static void assertMatches(int expected, int actual, String what) { } private static void testPinnedEvacuation(int younGCsBeforeUnpin, int expectedSkipEvents, int expectedDropEvents, int expectedReclaimEvents) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-Xbootclasspath/a:.", - "-Xmx32M", - "-Xmn16M", - "-XX:G1NumCollectionsKeepPinned=2", - "-XX:+VerifyAfterGC", - "-Xlog:gc,gc+ergo+cset=trace", - TestObjectPin.class.getName(), - String.valueOf(younGCsBeforeUnpin)); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:.", + "-Xmx32M", + "-Xmn16M", + "-XX:G1NumCollectionsKeepPinned=2", + "-XX:+VerifyAfterGC", + "-Xlog:gc,gc+ergo+cset=trace", + TestObjectPin.class.getName(), + String.valueOf(younGCsBeforeUnpin)); + System.out.println(output.getStdout()); output.shouldHaveExitValue(0); @@ -128,4 +127,3 @@ public static void main(String[] args) { wb.youngGC(); } } - diff --git a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedOldObjectsEvacuation.java b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedOldObjectsEvacuation.java index 86f7a62ef70..f30b3e8a7a5 100644 --- a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedOldObjectsEvacuation.java +++ b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedOldObjectsEvacuation.java @@ -257,24 +257,23 @@ private static void testPinnedEvacuation(int youngGCsBeforeUnpin, int expectedDropEvents, int expectedMarkingReclaimEvents, int expectedRetainedReclaimEvents) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-Xbootclasspath/a:.", - "-Xmx32M", - "-Xmn16M", - "-XX:MarkSweepDeadRatio=0", - "-XX:G1NumCollectionsKeepPinned=3", - "-XX:+UnlockExperimentalVMOptions", - // Take all old regions to make sure that the pinned one is included in the collection set. - "-XX:G1MixedGCLiveThresholdPercent=100", - "-XX:G1HeapWastePercent=0", - "-XX:+VerifyAfterGC", - "-Xlog:gc,gc+ergo+cset=trace", - TestObjectPin.class.getName(), - String.valueOf(youngGCsBeforeUnpin)); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:.", + "-Xmx32M", + "-Xmn16M", + "-XX:MarkSweepDeadRatio=0", + "-XX:G1NumCollectionsKeepPinned=3", + "-XX:+UnlockExperimentalVMOptions", + // Take all old regions to make sure that the pinned one is included in the collection set. + "-XX:G1MixedGCLiveThresholdPercent=100", + "-XX:G1HeapWastePercent=0", + "-XX:+VerifyAfterGC", + "-Xlog:gc,gc+ergo+cset=trace", + TestObjectPin.class.getName(), + String.valueOf(youngGCsBeforeUnpin)); + System.out.println(output.getStdout()); output.shouldHaveExitValue(0); @@ -334,4 +333,3 @@ public static void main(String[] args) { wb.youngGC(); } } - diff --git a/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java b/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java index ecceca21f2b..4e18e29d155 100644 --- a/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java +++ b/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java @@ -108,7 +108,7 @@ private static void runTest(int wastePct, int plabSize, int parGCThreads, int he "-XX:" + (plabIsFixed ? "-" : "+") + "ResizePLAB", "-XX:MaxHeapSize=" + heapSize + "m"); testOptions.add(AppPLABEvacuationFailure.class.getName()); - OutputAnalyzer out = ProcessTools.executeTestJvm(testOptions); + OutputAnalyzer out = ProcessTools.executeTestJava(testOptions); appPlabEvacFailureOutput = out.getOutput(); if (out.getExitValue() != 0) { diff --git a/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java b/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java index 785e07f8df5..f0549623789 100644 --- a/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java +++ b/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java @@ -117,7 +117,7 @@ public static void main(String[] args) throws Throwable { testCase.print(System.out); List options = PLABUtils.prepareOptions(testCase.toOptions()); options.add(AppPLABPromotion.class.getName()); - OutputAnalyzer out = ProcessTools.executeTestJvm(options); + OutputAnalyzer out = ProcessTools.executeTestJava(options); PLABUtils.commonCheck(out); output = out.getOutput(); checkResults(testCase); diff --git a/test/hotspot/jtreg/gc/g1/plab/TestPLABResize.java b/test/hotspot/jtreg/gc/g1/plab/TestPLABResize.java index 0c9ebb12e82..82246d790f4 100644 --- a/test/hotspot/jtreg/gc/g1/plab/TestPLABResize.java +++ b/test/hotspot/jtreg/gc/g1/plab/TestPLABResize.java @@ -87,7 +87,7 @@ public static void main(String[] args) throws Throwable { testCase.print(System.out); List options = PLABUtils.prepareOptions(testCase.toOptions()); options.add(AppPLABResize.class.getName()); - OutputAnalyzer out = ProcessTools.executeTestJvm(options); + OutputAnalyzer out = ProcessTools.executeTestJava(options); PLABUtils.commonCheck(out); checkResults(out.getOutput(), testCase); } diff --git a/test/hotspot/jtreg/gc/logging/TestDeprecatedPrintFlags.java b/test/hotspot/jtreg/gc/logging/TestDeprecatedPrintFlags.java index 04607502a22..78089ea6452 100644 --- a/test/hotspot/jtreg/gc/logging/TestDeprecatedPrintFlags.java +++ b/test/hotspot/jtreg/gc/logging/TestDeprecatedPrintFlags.java @@ -42,8 +42,7 @@ public class TestDeprecatedPrintFlags { public static void testPrintGC() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintGC", DoGC.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+PrintGC", DoGC.class.getName()); output.shouldContain("-XX:+PrintGC is deprecated. Will use -Xlog:gc instead."); output.shouldNotContain("PrintGCDetails"); output.stdoutShouldMatch("\\[info.*\\]\\[gc *\\]"); @@ -52,8 +51,7 @@ public static void testPrintGC() throws Exception { } public static void testPrintGCDetails() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintGCDetails", DoGC.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+PrintGCDetails", DoGC.class.getName()); output.shouldContain("-XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead."); output.shouldNotContain("PrintGC is deprecated"); output.stdoutShouldMatch("\\[info.*\\]\\[gc *\\]"); @@ -63,8 +61,7 @@ public static void testPrintGCDetails() throws Exception { public static void testXloggc() throws Exception { String fileName = "gc-test.log"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xloggc:" + fileName, DoGC.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-Xloggc:" + fileName, DoGC.class.getName()); output.shouldContain("-Xloggc is deprecated. Will use -Xlog:gc:gc-test.log instead."); output.shouldNotContain("PrintGCDetails"); output.shouldNotContain("PrintGC"); @@ -80,8 +77,7 @@ public static void testXloggc() throws Exception { public static void testXloggcWithPrintGCDetails() throws Exception { String fileName = "gc-test.log"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintGCDetails", "-Xloggc:" + fileName, DoGC.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+PrintGCDetails", "-Xloggc:" + fileName, DoGC.class.getName()); output.shouldContain("-XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead."); output.shouldContain("-Xloggc is deprecated. Will use -Xlog:gc:gc-test.log instead."); output.shouldNotContain("PrintGC is deprecated"); diff --git a/test/hotspot/jtreg/gc/logging/TestGCId.java b/test/hotspot/jtreg/gc/logging/TestGCId.java index dca1681e0e8..b1015f46435 100644 --- a/test/hotspot/jtreg/gc/logging/TestGCId.java +++ b/test/hotspot/jtreg/gc/logging/TestGCId.java @@ -73,9 +73,9 @@ private static void verifyContainsGCIDs(OutputAnalyzer output) { } private static void testGCId(String gcFlag) throws Exception { - ProcessBuilder pb_default = - ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", "-XX:+" + gcFlag, "-Xlog:gc", "-Xmx10M", GCTest.class.getName()); - verifyContainsGCIDs(new OutputAnalyzer(pb_default.start())); + OutputAnalyzer output = + ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+" + gcFlag, "-Xlog:gc", "-Xmx10M", GCTest.class.getName()); + verifyContainsGCIDs(output); } static class GCTest { diff --git a/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java b/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java index b67063091fb..044ad1cf9f5 100644 --- a/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java +++ b/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java @@ -93,24 +93,24 @@ private static boolean check(String line) { } private static void testMetaSpaceUpdate() throws Exception { - ProcessBuilder pb = - ProcessTools.createTestJavaProcessBuilder( - "-Xlog:gc*", - "-Xbootclasspath/a:.", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-Xmx1000M", - "-Xms1000M", - StressMetaSpace.class.getName()); - OutputAnalyzer output = null; try { - output = new OutputAnalyzer(pb.start()); + output = ProcessTools.executeTestJava( + "-Xlog:gc*", + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xmx1000M", + "-Xms1000M", + StressMetaSpace.class.getName()); + verifyContainsMetaSpaceUpdate(output); } catch (Exception e) { // For error diagnosis: print and throw. e.printStackTrace(); - output.reportDiagnosticSummary(); + if (output != null) { + output.reportDiagnosticSummary(); + } throw e; } } diff --git a/test/hotspot/jtreg/gc/logging/TestPrintReferences.java b/test/hotspot/jtreg/gc/logging/TestPrintReferences.java index 99932bc68a6..96e0e7f14d4 100644 --- a/test/hotspot/jtreg/gc/logging/TestPrintReferences.java +++ b/test/hotspot/jtreg/gc/logging/TestPrintReferences.java @@ -67,11 +67,10 @@ static String indent(int count) { } public static void testRefs() throws Exception { - ProcessBuilder pb_enabled = ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:gc+ref+phases=debug", - "-XX:+UseG1GC", - "-Xmx32M", - GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-Xlog:gc+ref+phases=debug", + "-XX:+UseG1GC", + "-Xmx32M", + GCTest.class.getName()); checkRefsLogFormat(output); @@ -95,14 +94,13 @@ private static void checkRefsLogFormat(OutputAnalyzer output) { } public static void testPhases(boolean parallelRefProcEnabled) throws Exception { - ProcessBuilder pb_enabled = ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:gc+phases+ref=debug", - "-XX:+UseG1GC", - "-Xmx32M", - "-XX:" + (parallelRefProcEnabled ? "+" : "-") + "ParallelRefProcEnabled", - "-XX:-UseDynamicNumberOfGCThreads", - "-XX:ParallelGCThreads=2", - GCTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-Xlog:gc+phases+ref=debug", + "-XX:+UseG1GC", + "-Xmx32M", + "-XX:" + (parallelRefProcEnabled ? "+" : "-") + "ParallelRefProcEnabled", + "-XX:-UseDynamicNumberOfGCThreads", + "-XX:ParallelGCThreads=2", + GCTest.class.getName()); checkLogFormat(output, parallelRefProcEnabled); checkLogValue(output); diff --git a/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java b/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java index 30553a7b8c6..5955006ec0f 100644 --- a/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java +++ b/test/hotspot/jtreg/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java @@ -77,9 +77,8 @@ public static void main(String[] args) throws Exception { } private static void run(ProcessBuilder pb) throws Exception { - Process p = pb.start(); - p.waitFor(); - int exitValue = p.exitValue(); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + int exitValue = output.getExitValue(); if (exitValue != 0) { throw new Exception("jmap -heap exited with error code: " + exitValue); } diff --git a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceSizeFlags.java b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceSizeFlags.java index eda71fa9c4b..7e6066557dd 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceSizeFlags.java +++ b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceSizeFlags.java @@ -84,13 +84,12 @@ private static MetaspaceFlags runAndGetValue(long maxMetaspaceSize, long metaspa } private static OutputAnalyzer run(long maxMetaspaceSize, long metaspaceSize) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + return ProcessTools.executeLimitedTestJava( "-XX:MaxMetaspaceSize=" + maxMetaspaceSize, "-XX:MetaspaceSize=" + metaspaceSize, "-XX:-UseLargePages", // Prevent us from using 2GB large pages on solaris + sparc. "-XX:+PrintFlagsFinal", "-version"); - return new OutputAnalyzer(pb.start()); } private static class MetaspaceFlags { diff --git a/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java b/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java index a87ed22e15b..458a90b08a4 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java +++ b/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java @@ -119,8 +119,7 @@ public static void main(String... args) throws Exception { System.out.println(" " + a); } - final ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(jvmArgs); - final OutputAnalyzer output = new OutputAnalyzer(pb.start()); + final OutputAnalyzer output = ProcessTools.executeLimitedTestJava(jvmArgs); System.out.println(output.getStdout()); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/serial/HeapChangeLogging.java b/test/hotspot/jtreg/gc/serial/HeapChangeLogging.java index 8480d046dfb..486fdbe0ed1 100644 --- a/test/hotspot/jtreg/gc/serial/HeapChangeLogging.java +++ b/test/hotspot/jtreg/gc/serial/HeapChangeLogging.java @@ -41,8 +41,7 @@ public class HeapChangeLogging { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m", "-Xmn100m", "-XX:+UseSerialGC", "-Xlog:gc", HeapFiller.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-Xmx128m", "-Xmn100m", "-XX:+UseSerialGC", "-Xlog:gc", HeapFiller.class.getName()); String stdout = output.getStdout(); System.out.println(stdout); Matcher stdoutMatcher = Pattern.compile(".*\\(Allocation Failure\\) [0-9]+[KMG]->[0-9]+[KMG]\\([0-9]+[KMG]\\)", Pattern.MULTILINE).matcher(stdout); diff --git a/test/hotspot/jtreg/gc/shenandoah/TestEvilSyncBug.java b/test/hotspot/jtreg/gc/shenandoah/TestEvilSyncBug.java index 67690d8cad5..8765105b5c0 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestEvilSyncBug.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestEvilSyncBug.java @@ -56,14 +56,13 @@ public static void main(String[] args) throws Exception { for (int c = 0; c < NUM_RUNS; c++) { Callable task = () -> { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xms128m", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-Xms128m", "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCHeuristics=aggressive", "TestEvilSyncBug", "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); return null; }; diff --git a/test/hotspot/jtreg/gc/shenandoah/TestJcmdHeapDump.java b/test/hotspot/jtreg/gc/shenandoah/TestJcmdHeapDump.java index cc5bc5d425e..40a36d0a5ef 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestJcmdHeapDump.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestJcmdHeapDump.java @@ -127,6 +127,7 @@ */ import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import java.io.File; @@ -141,11 +142,7 @@ public static void main(String[] args) { jcmd.addToolArg(dumpFileName); try { - ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand()); - Process jcmdProc = pb.start(); - - OutputAnalyzer output = new OutputAnalyzer(jcmdProc); - jcmdProc.waitFor(); + OutputAnalyzer output = ProcessTools.executeProcess(jcmd.getCommand()); output.shouldHaveExitValue(0); } catch (Exception e) { throw new RuntimeException("Test failed: " + e); diff --git a/test/hotspot/jtreg/gc/shenandoah/TestObjItrWithHeapDump.java b/test/hotspot/jtreg/gc/shenandoah/TestObjItrWithHeapDump.java index c0161b7a238..a0612a60a9f 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestObjItrWithHeapDump.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestObjItrWithHeapDump.java @@ -41,9 +41,8 @@ public static void testWith(String... args) throws Exception { String[] cmds = Arrays.copyOf(args, args.length + 2); cmds[args.length] = TestObjItrWithHeapDump.class.getName(); cmds[args.length + 1] = "test"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(cmds); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); output.shouldContain("Class Histogram (before full gc)"); output.shouldContain("Class Histogram (after full gc)"); diff --git a/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java b/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java index b65aa0cd0b4..3a5780069ef 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java @@ -42,9 +42,8 @@ public static void testWith(String msg, boolean periodic, String... args) throws String[] cmds = Arrays.copyOf(args, args.length + 2); cmds[args.length] = TestPeriodicGC.class.getName(); cmds[args.length + 1] = "test"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(cmds); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); if (periodic && !output.getOutput().contains("Trigger: Time since last GC")) { throw new AssertionError(msg + ": Should have periodic GC in logs"); diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargeObj.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargeObj.java index 1057eb4a977..f9e660cb200 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargeObj.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargeObj.java @@ -55,27 +55,25 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx16m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestAllocLargeObj.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(1); analyzer.shouldContain("java.lang.OutOfMemoryError: Java heap space"); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx1g", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestAllocLargeObj.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); analyzer.shouldNotContain("java.lang.OutOfMemoryError: Java heap space"); } diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargerThanHeap.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargerThanHeap.java index 1567e3d05da..a87fda5c98d 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargerThanHeap.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocLargerThanHeap.java @@ -50,27 +50,25 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx16m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestAllocLargerThanHeap.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(1); analyzer.shouldContain("java.lang.OutOfMemoryError: Java heap space"); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx1g", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestAllocLargerThanHeap.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); analyzer.shouldNotContain("java.lang.OutOfMemoryError: Java heap space"); } diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocSmallObj.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocSmallObj.java index bc32c1f0aa0..572351b498f 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocSmallObj.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestAllocSmallObj.java @@ -54,27 +54,25 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx16m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestAllocSmallObj.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(1); analyzer.shouldContain("java.lang.OutOfMemoryError: Java heap space"); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx1g", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestAllocSmallObj.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); analyzer.shouldNotContain("java.lang.OutOfMemoryError: Java heap space"); } diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java index beb57b0b401..9d17e916089 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestClassLoaderLeak.java @@ -99,9 +99,7 @@ public static void testWith(boolean shouldPass, String... args) throws Exception pbArgs.add(TestClassLoaderLeak.class.getName()); pbArgs.add("test"); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(pbArgs.toArray(new String[0])); - - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava(pbArgs.toArray(new String[0])); if (shouldPass) { analyzer.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/shenandoah/oom/TestThreadFailure.java b/test/hotspot/jtreg/gc/shenandoah/oom/TestThreadFailure.java index 75cb2d5c31a..fea5761df2f 100644 --- a/test/hotspot/jtreg/gc/shenandoah/oom/TestThreadFailure.java +++ b/test/hotspot/jtreg/gc/shenandoah/oom/TestThreadFailure.java @@ -62,14 +62,13 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer analyzer = ProcessTools.executeLimitedTestJava( "-Xmx32m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", TestThreadFailure.class.getName(), "test"); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); analyzer.shouldContain("java.lang.OutOfMemoryError"); analyzer.shouldContain("All good"); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestArgumentRanges.java b/test/hotspot/jtreg/gc/shenandoah/options/TestArgumentRanges.java index 2cc2c2c2197..597d9a74c1d 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestArgumentRanges.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestArgumentRanges.java @@ -46,36 +46,33 @@ public static void main(String[] args) throws Exception { private static void testHeuristics() throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCHeuristics=aggressive", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCHeuristics=static", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCHeuristics=fluff", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Unknown -XX:ShenandoahGCHeuristics option"); output.shouldHaveExitValue(1); } @@ -83,47 +80,43 @@ private static void testHeuristics() throws Exception { private static void testRange(String option, int min, int max) throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:" + option + "=" + (max + 1), "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:" + option + "=" + max, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:" + option + "=" + (min - 1), "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:" + option + "=" + min, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java b/test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java index c575b51084c..bf49ad3ec9c 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java @@ -43,8 +43,7 @@ public static void testWith(String msg, boolean cu, boolean cuConc, String... ar cmds[args.length] = "-Xmx128m"; cmds[args.length + 1] = "-XX:+PrintFlagsFinal"; cmds[args.length + 2] = "-version"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(cmds); output.shouldHaveExitValue(0); output.shouldContain("ClassUnloading"); output.shouldContain("ClassUnloadingWithConcurrentMark"); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGC.java b/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGC.java index 49e7c417130..7fe5d56f7de 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGC.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGC.java @@ -60,14 +60,13 @@ public static void main(String[] args) throws Exception { }; { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xlog:gc", TestExplicitGC.class.getName(), "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); for (String p : full) { output.shouldNotContain(p); } @@ -77,7 +76,7 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", @@ -85,7 +84,6 @@ public static void main(String[] args) throws Exception { "-XX:+DisableExplicitGC", TestExplicitGC.class.getName(), "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); for (String p : full) { output.shouldNotContain(p); } @@ -95,7 +93,7 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", @@ -103,7 +101,6 @@ public static void main(String[] args) throws Exception { "-XX:+ExplicitGCInvokesConcurrent", TestExplicitGC.class.getName(), "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); for (String p : full) { output.shouldNotContain(p); } @@ -113,7 +110,7 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", @@ -121,7 +118,6 @@ public static void main(String[] args) throws Exception { "-XX:-ExplicitGCInvokesConcurrent", TestExplicitGC.class.getName(), "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); for (String p : full) { output.shouldContain(p); } @@ -131,7 +127,7 @@ public static void main(String[] args) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", @@ -140,7 +136,6 @@ public static void main(String[] args) throws Exception { "-XX:ShenandoahGCMode=iu", TestExplicitGC.class.getName(), "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); for (String p : full) { output.shouldNotContain(p); } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGCNoConcurrent.java b/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGCNoConcurrent.java index 6499457b667..176e4a2ca7a 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGCNoConcurrent.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestExplicitGCNoConcurrent.java @@ -60,7 +60,7 @@ public static void main(String[] args) throws Exception { }; for (String opt : opts) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", @@ -70,7 +70,6 @@ public static void main(String[] args) throws Exception { "-XX:ShenandoahGCHeuristics=passive", TestExplicitGCNoConcurrent.class.getName(), "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); for (String p : concurrent) { output.shouldNotContain(p); } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestHeuristicsUnlock.java b/test/hotspot/jtreg/gc/shenandoah/options/TestHeuristicsUnlock.java index c9f1c75b4e1..9d0065fe803 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestHeuristicsUnlock.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestHeuristicsUnlock.java @@ -52,7 +52,7 @@ public static void main(String[] args) throws Exception { private static void testWith(String h, Mode mode) throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:-UnlockDiagnosticVMOptions", "-XX:-UnlockExperimentalVMOptions", @@ -60,7 +60,6 @@ private static void testWith(String h, Mode mode) throws Exception { h, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (mode) { case PRODUCT: output.shouldHaveExitValue(0); @@ -73,7 +72,7 @@ private static void testWith(String h, Mode mode) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:-UnlockExperimentalVMOptions", @@ -81,7 +80,6 @@ private static void testWith(String h, Mode mode) throws Exception { h, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (mode) { case PRODUCT: case DIAGNOSTIC: @@ -94,7 +92,7 @@ private static void testWith(String h, Mode mode) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:-UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -102,7 +100,6 @@ private static void testWith(String h, Mode mode) throws Exception { h, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (mode) { case PRODUCT: case EXPERIMENTAL: diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java index 523f434dbbd..47d4115ce74 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java @@ -38,12 +38,11 @@ public class TestHumongousThresholdArgs { public static void main(String[] args) throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } @@ -51,24 +50,22 @@ public static void main(String[] args) throws Exception { int[] invalid = new int[] {-100, -1, 0, 101, 1000}; for (int v : valid) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahHumongousThreshold=" + v, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } for (int v : invalid) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahHumongousThreshold=" + v, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(1); } } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestLoopMiningArguments.java b/test/hotspot/jtreg/gc/shenandoah/options/TestLoopMiningArguments.java index 79452b6cbc5..6d37b2877da 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestLoopMiningArguments.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestLoopMiningArguments.java @@ -44,8 +44,7 @@ public static void testWith(String msg, boolean cls, int iters, String... args) cmds[args.length] = "-Xmx128m"; cmds[args.length + 1] = "-XX:+PrintFlagsFinal"; cmds[args.length + 2] = "-version"; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(cmds); output.shouldHaveExitValue(0); output.shouldContain("UseCountedLoopSafepoints"); output.shouldContain("LoopStripMiningIter"); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestModeUnlock.java b/test/hotspot/jtreg/gc/shenandoah/options/TestModeUnlock.java index 0c8fea7f993..802038363b5 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestModeUnlock.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestModeUnlock.java @@ -51,7 +51,7 @@ public static void main(String[] args) throws Exception { private static void testWith(String h, Mode mode) throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:-UnlockDiagnosticVMOptions", "-XX:-UnlockExperimentalVMOptions", @@ -59,7 +59,6 @@ private static void testWith(String h, Mode mode) throws Exception { h, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (mode) { case PRODUCT: output.shouldHaveExitValue(0); @@ -72,7 +71,7 @@ private static void testWith(String h, Mode mode) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:-UnlockExperimentalVMOptions", @@ -80,7 +79,6 @@ private static void testWith(String h, Mode mode) throws Exception { h, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (mode) { case PRODUCT: case DIAGNOSTIC: @@ -93,7 +91,7 @@ private static void testWith(String h, Mode mode) throws Exception { } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:-UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -101,7 +99,6 @@ private static void testWith(String h, Mode mode) throws Exception { h, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); switch (mode) { case PRODUCT: case EXPERIMENTAL: diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java index 79d0b517e89..a8d5155584b 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java @@ -45,113 +45,103 @@ public static void main(String[] args) throws Exception { private static void testInvalidRegionSizes() throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms4m", "-Xmx1g", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms8m", "-Xmx1g", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahRegionSize=200m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahRegionSize option"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahRegionSize=9m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahRegionSize=255K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahRegionSize option"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahRegionSize=260K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms1g", "-Xmx1g", "-XX:ShenandoahRegionSize=32M", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms1g", "-Xmx1g", "-XX:ShenandoahRegionSize=64M", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahRegionSize option"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms1g", "-Xmx1g", "-XX:ShenandoahRegionSize=256K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms1g", "-Xmx1g", "-XX:ShenandoahRegionSize=128K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahRegionSize option"); output.shouldHaveExitValue(1); } @@ -160,49 +150,45 @@ private static void testInvalidRegionSizes() throws Exception { private static void testMinRegionSize() throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahMinRegionSize=255K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize option"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahMinRegionSize=1M", "-XX:ShenandoahMaxRegionSize=260K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahMinRegionSize=200m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize option"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahMinRegionSize=9m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } @@ -211,26 +197,24 @@ private static void testMinRegionSize() throws Exception { private static void testMaxRegionSize() throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahMaxRegionSize=255K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahMaxRegionSize option"); output.shouldHaveExitValue(1); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms100m", "-Xmx1g", "-XX:ShenandoahMinRegionSize=1M", "-XX:ShenandoahMaxRegionSize=260K", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize"); output.shouldHaveExitValue(1); } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java index 5b34bfab3a0..094e62f53f3 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java @@ -89,8 +89,7 @@ public static void main(String[] args) throws Exception { pool.submit(() -> { try { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(conf.toArray(new String[0])); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(conf.toArray(new String[0])); output.shouldHaveExitValue(0); } catch (Exception e) { e.printStackTrace(); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestSoftMaxHeapSize.java b/test/hotspot/jtreg/gc/shenandoah/options/TestSoftMaxHeapSize.java index 78bbf75189c..212ffb41037 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestSoftMaxHeapSize.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestSoftMaxHeapSize.java @@ -38,35 +38,32 @@ public class TestSoftMaxHeapSize { public static void main(String[] args) throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms4m", "-Xmx128m", "-XX:SoftMaxHeapSize=4m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms4m", "-Xmx128m", "-XX:SoftMaxHeapSize=128m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions", + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-Xms4m", "-Xmx128m", "-XX:SoftMaxHeapSize=129m", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(1); output.shouldContain("SoftMaxHeapSize must be less than or equal to the maximum heap size"); } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCounts.java b/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCounts.java index f7f9ee56b59..90985eb4c4d 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCounts.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCounts.java @@ -45,7 +45,7 @@ public static void main(String[] args) throws Exception { } private static void testWith(int conc, int par) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -53,7 +53,6 @@ private static void testWith(int conc, int par) throws Exception { "-XX:ConcGCThreads=" + conc, "-XX:ParallelGCThreads=" + par, "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); if (conc == 0) { output.shouldContain("Shenandoah expects ConcGCThreads > 0"); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCountsOverride.java b/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCountsOverride.java index 5e63595e726..b3d8ba34567 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCountsOverride.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestThreadCountsOverride.java @@ -38,7 +38,7 @@ public class TestThreadCountsOverride { public static void main(String[] args) throws Exception { { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -46,14 +46,13 @@ public static void main(String[] args) throws Exception { "-XX:ParallelGCThreads=1", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("ParallelGCThreads(.*)= 1 "); output.shouldHaveExitValue(0); } { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -61,7 +60,6 @@ public static void main(String[] args) throws Exception { "-XX:ConcGCThreads=1", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldMatch("ConcGCThreads(.*)= 1 "); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java index 0e913375534..aa6b7935649 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java @@ -63,7 +63,7 @@ public static void main(String[] args) throws Exception { private static void shouldFailAll(String h, String[] barriers) throws Exception { for (String b : barriers) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -72,7 +72,6 @@ private static void shouldFailAll(String h, String[] barriers) throws Exception "-XX:-" + b, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotHaveExitValue(0); output.shouldContain("GC mode needs "); output.shouldContain("to work correctly"); @@ -81,7 +80,7 @@ private static void shouldFailAll(String h, String[] barriers) throws Exception private static void shouldPassAll(String h, String[] barriers) throws Exception { for (String b : barriers) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -90,7 +89,6 @@ private static void shouldPassAll(String h, String[] barriers) throws Exception "-XX:-" + b, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java index 84645621eb4..486860728ab 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java @@ -55,7 +55,7 @@ public static void main(String[] args) throws Exception { private static void shouldFailAll(String h, String[] barriers) throws Exception { for (String b : barriers) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -64,7 +64,6 @@ private static void shouldFailAll(String h, String[] barriers) throws Exception "-XX:+" + b, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotHaveExitValue(0); output.shouldContain("GC mode needs "); output.shouldContain("to work correctly"); @@ -73,7 +72,7 @@ private static void shouldFailAll(String h, String[] barriers) throws Exception private static void shouldPassAll(String h, String[] barriers) throws Exception { for (String b : barriers) { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-Xmx128m", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", @@ -82,7 +81,6 @@ private static void shouldPassAll(String h, String[] barriers) throws Exception "-XX:+" + b, "-version" ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java index 83f211ad5fa..bfe19e2c9c5 100644 --- a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java +++ b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java @@ -61,8 +61,8 @@ public static void main(String[] args) throws Exception { "-XX:+PrintNMTStatistics" )); baseargs.addAll(Arrays.asList(args)); baseargs.add(GCTest.class.getName()); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(baseargs); - verifySymbolMemoryUsageNotTooHigh(new OutputAnalyzer(pb.start())); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(baseargs); + verifySymbolMemoryUsageNotTooHigh(output); } private static void verifySymbolMemoryUsageNotTooHigh(OutputAnalyzer output) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java index 2a02039c60e..70544e8af31 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java @@ -101,8 +101,7 @@ public static void main(String[] args) throws Exception { "-Dregionsize=" + regionSize, TestStressG1HumongousImpl.class.getName() ); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(options); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(options); output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java b/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java index 2f61c166cb8..d3575e8cd4b 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java @@ -59,8 +59,7 @@ public static void main(String[] args) throws Exception { "-XX:+UseG1GC", StressUncommit.class.getName() ); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(options); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(options); output.shouldHaveExitValue(0); output.shouldMatch("Uncommit regions"); output.outputTo(System.out); diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java index d18548abdfe..e819501aca3 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java +++ b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java @@ -169,7 +169,7 @@ public static void main(String args[]) throws Exception { finalArgs.addAll(Arrays.asList(args)); // GC and other options obtained from test framework. - OutputAnalyzer output = ProcessTools.executeTestJvm(finalArgs); + OutputAnalyzer output = ProcessTools.executeTestJava(finalArgs); output.shouldHaveExitValue(0); //System.out.println("------------- begin stdout ----------------"); //System.out.println(output.getStdout()); diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java deleted file mode 100644 index 36b9a59fde6..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package gc.stress.gclocker; - -// Stress the GC locker by calling GetPrimitiveArrayCritical while -// concurrently filling up old gen. - -import java.lang.management.MemoryPoolMXBean; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryUsage; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Queue; - -final class ThreadUtils { - public static void sleep(long durationMS) { - try { - Thread.sleep(durationMS); - } catch (Exception e) { - } - } -} - -class Filler { - private static final int SIZE = 250000; - - private int[] i1 = new int[SIZE]; - private int[] i2 = new int[SIZE]; - private short[] s1 = new short[SIZE]; - private short[] s2 = new short[SIZE]; - - private Map map = new HashMap<>(); - - public Filler() { - for (int i = 0; i < 10000; i++) { - map.put(new Object(), new Object()); - } - } -} - -class Exitable { - private volatile boolean shouldExit = false; - - protected boolean shouldExit() { - return shouldExit; - } - - public void exit() { - shouldExit = true; - } -} - -class MemoryWatcher { - private MemoryPoolMXBean bean; - private final int thresholdPromille = 750; - private final int criticalThresholdPromille = 800; - private final long minGCWaitNanos = 1_000_000_000L; - private final long minFreeWaitElapsedNanos = 30L * 1_000_000_000L; - private final long minFreeCriticalWaitNanos; - - private int lastUsage = 0; - private long lastGCDetectedNanos = System.nanoTime(); - private long lastFreeNanos = System.nanoTime(); - - public MemoryWatcher(String mxBeanName, long minFreeCriticalWaitNanos) { - this.minFreeCriticalWaitNanos = minFreeCriticalWaitNanos; - List memoryBeans = ManagementFactory.getMemoryPoolMXBeans(); - for (MemoryPoolMXBean bean : memoryBeans) { - if (bean.getName().equals(mxBeanName)) { - this.bean = bean; - break; - } - } - } - - private int getMemoryUsage() { - if (bean == null) { - Runtime r = Runtime.getRuntime(); - float free = (float) r.freeMemory() / r.maxMemory(); - return Math.round((1 - free) * 1000); - } else { - MemoryUsage usage = bean.getUsage(); - float used = (float) usage.getUsed() / usage.getCommitted(); - return Math.round(used * 1000); - } - } - - public synchronized boolean shouldFreeUpSpace() { - int usage = getMemoryUsage(); - long nowNanos = System.nanoTime(); - - boolean detectedGC = false; - if (usage < lastUsage) { - lastGCDetectedNanos = nowNanos; - detectedGC = true; - } - - lastUsage = usage; - - long elapsedNanos = nowNanos - lastFreeNanos; - long timeSinceLastGCNanos = nowNanos - lastGCDetectedNanos; - - if (usage > criticalThresholdPromille && elapsedNanos > minFreeCriticalWaitNanos) { - lastFreeNanos = nowNanos; - return true; - } else if (usage > thresholdPromille && !detectedGC) { - if (elapsedNanos > minFreeWaitElapsedNanos || timeSinceLastGCNanos > minGCWaitNanos) { - lastFreeNanos = nowNanos; - return true; - } - } - - return false; - } -} - -class MemoryUser extends Exitable implements Runnable { - private final Queue cache = new ArrayDeque(); - private final MemoryWatcher watcher; - - private void load() { - if (watcher.shouldFreeUpSpace()) { - int toRemove = cache.size() / 5; - for (int i = 0; i < toRemove; i++) { - cache.remove(); - } - } - cache.add(new Filler()); - } - - public MemoryUser(String mxBeanName, long minFreeCriticalWaitNanos) { - watcher = new MemoryWatcher(mxBeanName, minFreeCriticalWaitNanos); - } - - @Override - public void run() { - for (int i = 0; i < 200; i++) { - load(); - } - - while (!shouldExit()) { - load(); - } - } -} - -class GCLockerStresser extends Exitable implements Runnable { - static native void fillWithRandomValues(byte[] array); - - @Override - public void run() { - byte[] array = new byte[1024 * 1024]; - while (!shouldExit()) { - fillWithRandomValues(array); - } - } -} - -public class TestGCLocker { - private static Exitable startGCLockerStresser(String name) { - GCLockerStresser task = new GCLockerStresser(); - - Thread thread = new Thread(task); - thread.setName(name); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - - return task; - } - - private static Exitable startMemoryUser(String mxBeanName, long minFreeCriticalWaitNanos) { - MemoryUser task = new MemoryUser(mxBeanName, minFreeCriticalWaitNanos); - - Thread thread = new Thread(task); - thread.setName("Memory User"); - thread.start(); - - return task; - } - - public static void main(String[] args) { - System.loadLibrary("TestGCLocker"); - - long durationMinutes = args.length > 0 ? Long.parseLong(args[0]) : 5; - String mxBeanName = args.length > 1 ? args[1] : null; - long minFreeCriticalWaitNanos = args.length > 2 - ? Integer.parseInt(args[2]) * 1_000_000L - : 500_000_000L; - - Exitable stresser1 = startGCLockerStresser("GCLockerStresser1"); - Exitable stresser2 = startGCLockerStresser("GCLockerStresser2"); - Exitable memoryUser = startMemoryUser(mxBeanName, minFreeCriticalWaitNanos); - - try { - Thread.sleep(durationMinutes * 60_000L); - } catch (InterruptedException e) { - throw new RuntimeException("Test Failure, did not except an InterruptedException", e); - } - - stresser1.exit(); - stresser2.exit(); - memoryUser.exit(); - } -} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java deleted file mode 100644 index 586fdc79881..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Red Hat, 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. - * - */ - -package gc.stress.gclocker; - -/* - * @test id=default - * @library / - * @requires vm.gc.Shenandoah - * @summary Stress Shenandoah's JNI handling by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC - * -XX:+ShenandoahVerify - * gc.stress.gclocker.TestGCLockerWithShenandoah - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC - * gc.stress.gclocker.TestGCLockerWithShenandoah - */ - -/* - * @test id=aggressive - * @library / - * @requires vm.gc.Shenandoah - * @summary Stress Shenandoah's JNI handling by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive - * -XX:+ShenandoahOOMDuringEvacALot - * gc.stress.gclocker.TestGCLockerWithShenandoah - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive - * -XX:+ShenandoahAllocFailureALot - * gc.stress.gclocker.TestGCLockerWithShenandoah - */ -public class TestGCLockerWithShenandoah { - public static void main(String[] args) { - String[] testArgs = {"2", "Shenandoah", "0"}; - TestGCLocker.main(testArgs); - } -} diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java index 31c11b66dfc..8b8fea1f2e3 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java @@ -299,8 +299,7 @@ private static OutputAnalyzer runTest(String... extraArgs) throws Exception { args.addAll(Arrays.asList(defaultArgs)); args.addAll(Arrays.asList(extraArgs)); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(args); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeTestJava(args); System.err.println(output.getStderr()); System.out.println(output.getStdout()); return output; diff --git a/test/hotspot/jtreg/gc/testlibrary/Helpers.java b/test/hotspot/jtreg/gc/testlibrary/Helpers.java index 225a5bda0e6..03d67e44455 100644 --- a/test/hotspot/jtreg/gc/testlibrary/Helpers.java +++ b/test/hotspot/jtreg/gc/testlibrary/Helpers.java @@ -25,6 +25,7 @@ import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; import jdk.test.whitebox.WhiteBox; import java.io.File; @@ -89,7 +90,7 @@ public static int detectByteArrayAllocationOverhead() { * @param source class source * @throws IOException if cannot write file to specified directory */ - public static void compileClass(String className, Path root, String source) throws IOException { + public static void compileClass(String className, Path root, String source) throws Exception { Path sourceFile = root.resolve(className + ".java"); Files.write(sourceFile, source.getBytes()); @@ -100,8 +101,7 @@ public static void compileClass(String className, Path root, String source) thro .addToolArg(System.getProperty("java.class.path") + File.pathSeparator + root.toAbsolutePath()) .addToolArg(sourceFile.toAbsolutePath().toString()); - ProcessBuilder pb = new ProcessBuilder(jar.getCommand()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + OutputAnalyzer output = ProcessTools.executeProcess(jar.getCommand()); output.shouldHaveExitValue(0); } @@ -199,12 +199,11 @@ public static String enumNameToClassName(String enumName) { * @param prefix prefix for service classes (ones we use to create chain of inheritance). * The names will be prefix_1, prefix_2,.., prefix_n * @return Class object of generated and compiled class loaded in specified class loader - * @throws IOException - * @throws ClassNotFoundException + * @throws Exception */ public static Class generateCompileAndLoad(ClassLoader classLoader, String className, long instanceSize, Path workDir, String prefix) - throws IOException, ClassNotFoundException { + throws Exception { generateByTemplateAndCompile(className, null, "public class ${ClassName} extends ${BaseClass} {\n${Fields}}\n", "", instanceSize, workDir, prefix); @@ -243,11 +242,11 @@ public static Class generateCompileAndLoad(ClassLoader classLoader, String cl * @param prefix prefix for service classes (ones we use to create chain of inheritance). * The names will be prefix_1, prefix_2,.., prefix_n * @return Class object of generated and compiled class loaded in specified class loader - * @throws IOException if cannot write or read to workDir + * @throws Exception if cannot write or read to workDir */ public static void generateByTemplateAndCompile(String className, String baseClass, String classTemplate, String constructorTemplate, long instanceSize, Path workDir, - String prefix) throws IOException { + String prefix) throws Exception { if (instanceSize % SIZE_OF_LONG != 0L) { throw new Error(String.format("Test bug: only sizes aligned by %d bytes are supported and %d was specified", diff --git a/test/hotspot/jtreg/gc/whitebox/TestWBGC.java b/test/hotspot/jtreg/gc/whitebox/TestWBGC.java index c2fe2633e4e..38f3593b638 100644 --- a/test/hotspot/jtreg/gc/whitebox/TestWBGC.java +++ b/test/hotspot/jtreg/gc/whitebox/TestWBGC.java @@ -43,7 +43,7 @@ public class TestWBGC { public static void main(String args[]) throws Exception { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + OutputAnalyzer output = ProcessTools.executeTestJava( "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", @@ -51,7 +51,6 @@ public static void main(String args[]) throws Exception { "-Xlog:gc", GCYoungTest.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); System.out.println(output.getStdout()); output.shouldHaveExitValue(0); output.shouldContain("WhiteBox Initiated Young GC"); diff --git a/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java index de3d1f585a7..3bf83d90768 100644 --- a/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java @@ -41,16 +41,16 @@ public static void main(String[] args) throws Exception { final String heapBackingFile = "Heap Backing File: " + directory; final String failedToCreateFile = "Failed to create file " + directory; - ProcessTools.executeProcess(ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xlog:gc*", - "-Xms32M", - "-Xmx32M", - "-XX:AllocateHeapAt=" + directory, - "-version")) - .shouldContain(exists ? heapBackingFile : failedToCreateFile) - .shouldNotContain(exists ? failedToCreateFile : heapBackingFile) - .shouldHaveExitValue(exists ? 0 : 1); + ProcessTools.executeLimitedTestJava( + "-XX:+UseZGC", + "-XX:-ZGenerational", + "-Xlog:gc*", + "-Xms32M", + "-Xmx32M", + "-XX:AllocateHeapAt=" + directory, + "-version") + .shouldContain(exists ? heapBackingFile : failedToCreateFile) + .shouldNotContain(exists ? failedToCreateFile : heapBackingFile) + .shouldHaveExitValue(exists ? 0 : 1); } } diff --git a/test/hotspot/jtreg/gc/x/TestHighUsage.java b/test/hotspot/jtreg/gc/x/TestHighUsage.java index 370d8031800..32b0af19e4b 100644 --- a/test/hotspot/jtreg/gc/x/TestHighUsage.java +++ b/test/hotspot/jtreg/gc/x/TestHighUsage.java @@ -85,15 +85,15 @@ public static void main(String[] args) throws Exception { } public static void main(String[] args) throws Exception { - ProcessTools.executeTestJvm("-XX:+UseZGC", - "-XX:-ZGenerational", - "-XX:-ZProactive", - "-Xms128M", - "-Xmx128M", - "-XX:ParallelGCThreads=1", - "-XX:ConcGCThreads=1", - "-Xlog:gc,gc+start", - Test.class.getName()) + ProcessTools.executeTestJava("-XX:+UseZGC", + "-XX:-ZGenerational", + "-XX:-ZProactive", + "-Xms128M", + "-Xmx128M", + "-XX:ParallelGCThreads=1", + "-XX:ConcGCThreads=1", + "-Xlog:gc,gc+start", + Test.class.getName()) .shouldNotContain("Allocation Stall") .shouldContain("High Usage") .shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java b/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java index 5a20ee8322a..cb8685d0d09 100644 --- a/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java +++ b/test/hotspot/jtreg/gc/x/TestPageCacheFlush.java @@ -68,16 +68,16 @@ public static void main(String[] args) throws Exception { } public static void main(String[] args) throws Exception { - ProcessTools.executeProcess(ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xms128M", - "-Xmx128M", - "-Xlog:gc,gc+init,gc+heap=debug", - Test.class.getName())) - .outputTo(System.out) - .errorTo(System.out) - .shouldContain("Page Cache Flushed:") - .shouldHaveExitValue(0); + ProcessTools.executeLimitedTestJava( + "-XX:+UseZGC", + "-XX:-ZGenerational", + "-Xms128M", + "-Xmx128M", + "-Xlog:gc,gc+init,gc+heap=debug", + Test.class.getName()) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("Page Cache Flushed:") + .shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/x/TestSmallHeap.java b/test/hotspot/jtreg/gc/x/TestSmallHeap.java index 0fc6477b59b..8fc6f07be39 100644 --- a/test/hotspot/jtreg/gc/x/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/x/TestSmallHeap.java @@ -53,16 +53,16 @@ public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception { for (var maxCapacity: args) { - ProcessTools.executeProcess(ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:-ZGenerational", - "-Xlog:gc,gc+init,gc+reloc,gc+heap", - "-Xmx" + maxCapacity, - Test.class.getName())) - .outputTo(System.out) - .errorTo(System.out) - .shouldContain("Success") - .shouldHaveExitValue(0); + ProcessTools.executeLimitedTestJava( + "-XX:+UseZGC", + "-XX:-ZGenerational", + "-Xlog:gc,gc+init,gc+reloc,gc+heap", + "-Xmx" + maxCapacity, + Test.class.getName()) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("Success") + .shouldHaveExitValue(0); } } } diff --git a/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java index f5a6113f6ff..9f47c4b60d3 100644 --- a/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java @@ -41,16 +41,16 @@ public static void main(String[] args) throws Exception { final String heapBackingFile = "Heap Backing File: " + directory; final String failedToCreateFile = "Failed to create file " + directory; - ProcessTools.executeProcess(ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:+ZGenerational", - "-Xlog:gc*", - "-Xms32M", - "-Xmx32M", - "-XX:AllocateHeapAt=" + directory, - "-version")) - .shouldContain(exists ? heapBackingFile : failedToCreateFile) - .shouldNotContain(exists ? failedToCreateFile : heapBackingFile) - .shouldHaveExitValue(exists ? 0 : 1); + ProcessTools.executeLimitedTestJava( + "-XX:+UseZGC", + "-XX:+ZGenerational", + "-Xlog:gc*", + "-Xms32M", + "-Xmx32M", + "-XX:AllocateHeapAt=" + directory, + "-version") + .shouldContain(exists ? heapBackingFile : failedToCreateFile) + .shouldNotContain(exists ? failedToCreateFile : heapBackingFile) + .shouldHaveExitValue(exists ? 0 : 1); } } diff --git a/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java b/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java index 629edccd496..387053b580a 100644 --- a/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java +++ b/test/hotspot/jtreg/gc/z/TestPageCacheFlush.java @@ -68,16 +68,16 @@ public static void main(String[] args) throws Exception { } public static void main(String[] args) throws Exception { - ProcessTools.executeProcess(ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:+ZGenerational", - "-Xms128M", - "-Xmx128M", - "-Xlog:gc,gc+init,gc+heap=debug", - Test.class.getName())) - .outputTo(System.out) - .errorTo(System.out) - .shouldContain("Page Cache Flushed:") - .shouldHaveExitValue(0); + ProcessTools.executeLimitedTestJava( + "-XX:+UseZGC", + "-XX:+ZGenerational", + "-Xms128M", + "-Xmx128M", + "-Xlog:gc,gc+init,gc+heap=debug", + Test.class.getName()) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("Page Cache Flushed:") + .shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/gc/z/TestSmallHeap.java b/test/hotspot/jtreg/gc/z/TestSmallHeap.java index bfe1c0310ca..354cd4164f1 100644 --- a/test/hotspot/jtreg/gc/z/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/z/TestSmallHeap.java @@ -53,16 +53,16 @@ public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception { for (var maxCapacity: args) { - ProcessTools.executeProcess(ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:+ZGenerational", - "-Xlog:gc,gc+init,gc+reloc,gc+heap", - "-Xmx" + maxCapacity, - Test.class.getName())) - .outputTo(System.out) - .errorTo(System.out) - .shouldContain("Success") - .shouldHaveExitValue(0); + ProcessTools.executeLimitedTestJava( + "-XX:+UseZGC", + "-XX:+ZGenerational", + "-Xlog:gc,gc+init,gc+reloc,gc+heap", + "-Xmx" + maxCapacity, + Test.class.getName()) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("Success") + .shouldHaveExitValue(0); } } } diff --git a/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java b/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java index 2993038faa5..f1a14f0cf90 100644 --- a/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java +++ b/test/hotspot/jtreg/gc/z/TestZForceDiscontiguousHeapReservations.java @@ -45,17 +45,17 @@ private static void testValue(int n) throws Exception { */ final int XmxInM = 2000; final int XmsInM = Math.min(16 * XmxInM / (n + 1), XmxInM); - OutputAnalyzer oa = ProcessTools.executeProcess(ProcessTools.createTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:+ZGenerational", - "-Xms" + XmsInM + "M", - "-Xmx" + XmxInM + "M", - "-Xlog:gc,gc+init", - "-XX:ZForceDiscontiguousHeapReservations=" + n, - "-version")) - .outputTo(System.out) - .errorTo(System.out) - .shouldHaveExitValue(0); + OutputAnalyzer oa = ProcessTools.executeTestJava( + "-XX:+UseZGC", + "-XX:+ZGenerational", + "-Xms" + XmsInM + "M", + "-Xmx" + XmxInM + "M", + "-Xlog:gc,gc+init", + "-XX:ZForceDiscontiguousHeapReservations=" + n, + "-version") + .outputTo(System.out) + .errorTo(System.out) + .shouldHaveExitValue(0); if (n > 1) { oa.shouldContain("Address Space Type: Discontiguous"); } diff --git a/test/hotspot/jtreg/gc/z/TestZNMT.java b/test/hotspot/jtreg/gc/z/TestZNMT.java index 066ebd063f6..db37a0e1e14 100644 --- a/test/hotspot/jtreg/gc/z/TestZNMT.java +++ b/test/hotspot/jtreg/gc/z/TestZNMT.java @@ -68,21 +68,21 @@ private static void testValue(int zForceDiscontiguousHeapReservations) throws Ex * reservations. */ final int XmsInM = Math.min(16 * XmxInM / (zForceDiscontiguousHeapReservations + 1), XmxInM); - OutputAnalyzer oa = ProcessTools.executeProcess(ProcessTools.createTestJavaProcessBuilder( - "-XX:+UseZGC", - "-XX:+ZGenerational", - "-Xms" + XmsInM + "M", - "-Xmx" + XmxInM + "M", - "-Xlog:gc,gc+init", - "-XX:ZForceDiscontiguousHeapReservations=" + zForceDiscontiguousHeapReservations, - "-XX:NativeMemoryTracking=detail", - "-XX:+PrintNMTStatistics", - Test.class.getName(), - Integer.toString(zForceDiscontiguousHeapReservations), - Integer.toString(XmxInM))) - .outputTo(System.out) - .errorTo(System.out) - .shouldHaveExitValue(0); + OutputAnalyzer oa = ProcessTools.executeTestJava( + "-XX:+UseZGC", + "-XX:+ZGenerational", + "-Xms" + XmsInM + "M", + "-Xmx" + XmxInM + "M", + "-Xlog:gc,gc+init", + "-XX:ZForceDiscontiguousHeapReservations=" + zForceDiscontiguousHeapReservations, + "-XX:NativeMemoryTracking=detail", + "-XX:+PrintNMTStatistics", + Test.class.getName(), + Integer.toString(zForceDiscontiguousHeapReservations), + Integer.toString(XmxInM)) + .outputTo(System.out) + .errorTo(System.out) + .shouldHaveExitValue(0); if (zForceDiscontiguousHeapReservations > 1) { oa.shouldContain("Address Space Type: Discontiguous"); } diff --git a/test/hotspot/jtreg/runtime/CommandLine/TestNullTerminatedFlags.java b/test/hotspot/jtreg/runtime/CommandLine/TestNullTerminatedFlags.java index e31a7e2cd17..6f7cc688068 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/TestNullTerminatedFlags.java +++ b/test/hotspot/jtreg/runtime/CommandLine/TestNullTerminatedFlags.java @@ -50,8 +50,7 @@ public class TestNullTerminatedFlags { "-Xshare:on", "-Xshare:auto", "-Xshare:off", - "-Xdebug", - "-Xnoagent" + "-Xdebug" }; public static void main(String args[]) throws Exception{ diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java b/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java similarity index 59% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java rename to test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java index 9de8fa88ca7..4b1d4fa3867 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java +++ b/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,22 +19,27 @@ * 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.stress.gclocker; - /* - * @test TestGCLockerWithSerial - * @library / - * @requires vm.gc.Serial - * @requires vm.flavor != "minimal" - * @summary Stress Serial's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseSerialGC gc.stress.gclocker.TestGCLockerWithSerial + * @test + * @bug 8321479 + * @summary VM should not crash with property "-D-D" + * @requires vm.flagless + * @library /test/lib + * @run driver UnrecognizedProperty */ -public class TestGCLockerWithSerial { - public static void main(String[] args) { - String[] testArgs = {"2", "Tenured Gen"}; - TestGCLocker.main(testArgs); + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class UnrecognizedProperty { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-D-D"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Usage: java"); + output.shouldHaveExitValue(1); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java index 3f26461643a..c32027f82b0 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java @@ -54,8 +54,8 @@ public static void main(String[] args) throws Throwable { // and don't terminate abruptly due to stack overflow error @Test public void testNativeExceptionReporting() throws Exception { - OutputAnalyzer output = ProcessTools.executeTestJvm( - // executeTestJvm doesn't seem to forward 'java.library.path' + OutputAnalyzer output = ProcessTools.executeTestJava( + // executeTestJava doesn't seem to forward 'java.library.path' "-Djava.library.path=" + System.getProperty("java.library.path"), Crasher.class.getName()); diff --git a/test/hotspot/jtreg/runtime/LoadLibrary/TestSunBootLibraryPath.java b/test/hotspot/jtreg/runtime/LoadLibrary/TestSunBootLibraryPath.java index 356064d79a4..deb2a000d3d 100644 --- a/test/hotspot/jtreg/runtime/LoadLibrary/TestSunBootLibraryPath.java +++ b/test/hotspot/jtreg/runtime/LoadLibrary/TestSunBootLibraryPath.java @@ -46,11 +46,11 @@ public static void main(String[] args) throws Exception { // Start a java process with this property set, and check that: // 1) The process failed and // 2) The error message was correct. - ProcessTools.executeTestJvm("-Dsun.boot.library.path=" + tooLongPath, - "TestSunBootLibraryPath", - "'Do-Nothing'") - .shouldNotHaveExitValue(0) - .stdoutShouldContain(expectedErrorMessage); + ProcessTools.executeTestJava("-Dsun.boot.library.path=" + tooLongPath, + "TestSunBootLibraryPath", + "'Do-Nothing'") + .shouldNotHaveExitValue(0) + .stdoutShouldContain(expectedErrorMessage); } else if (!args[0].equals("Do-Nothing")) { // Fail, to prevent accidental args from causing accidental test passing. throw new IllegalArgumentException("Test was launched with an invalid argument."); diff --git a/test/hotspot/jtreg/runtime/Shutdown/ShutdownTest.java b/test/hotspot/jtreg/runtime/Shutdown/ShutdownTest.java index 30b1ebe252a..68dc6b2e1a7 100644 --- a/test/hotspot/jtreg/runtime/Shutdown/ShutdownTest.java +++ b/test/hotspot/jtreg/runtime/Shutdown/ShutdownTest.java @@ -66,7 +66,7 @@ public static void main(String args[]) { private static void startVM(String... options) throws Throwable { // Combine VM flags given from command-line and your additional options - OutputAnalyzer output = ProcessTools.executeTestJvm(options); + OutputAnalyzer output = ProcessTools.executeTestJava(options); output.shouldContain("- ShutdownTest -"); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java b/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java index 57599cffd62..fcf48a7a2d7 100644 --- a/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java +++ b/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java @@ -41,6 +41,7 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.lang.foreign.MemorySegment; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.MappedByteBuffer; @@ -60,6 +61,8 @@ public class InternalErrorTest { private static final String failureMsg1 = "InternalError not thrown"; private static final String failureMsg2 = "Wrong InternalError: "; + private static final int NUM_TESTS = 4; + public static void main(String[] args) throws Throwable { Unsafe unsafe = Unsafe.getUnsafe(); @@ -71,9 +74,9 @@ public static void main(String[] args) throws Throwable { s.append("1"); } Files.write(file.toPath(), s.toString().getBytes()); - FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel(); + FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); MappedByteBuffer buffer = - fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); + fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size()); // Get address of mapped memory. long mapAddr = 0; @@ -86,13 +89,13 @@ public static void main(String[] args) throws Throwable { } long allocMem = unsafe.allocateMemory(4000); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < NUM_TESTS; i++) { test(buffer, unsafe, mapAddr, allocMem, i); } Files.write(file.toPath(), "2".getBytes()); buffer.position(buffer.position() + pageSize); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < NUM_TESTS; i++) { try { test(buffer, unsafe, mapAddr, allocMem, i); WhiteBox.getWhiteBox().forceSafepoint(); @@ -107,7 +110,7 @@ public static void main(String[] args) throws Throwable { Method m = InternalErrorTest.class.getMethod("test", MappedByteBuffer.class, Unsafe.class, long.class, long.class, int.class); WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 3); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < NUM_TESTS; i++) { try { test(buffer, unsafe, mapAddr, allocMem, i); WhiteBox.getWhiteBox().forceSafepoint(); @@ -121,7 +124,7 @@ public static void main(String[] args) throws Throwable { WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 4); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < NUM_TESTS; i++) { try { test(buffer, unsafe, mapAddr, allocMem, i); WhiteBox.getWhiteBox().forceSafepoint(); @@ -143,13 +146,18 @@ public static void test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, lo buffer.get(new byte[8]); break; case 1: - // testing Unsafe.copySwapMemory, trying to access next page after truncation. + // testing Unsafe.copySwapMemory, trying to access next page after truncation. unsafe.copySwapMemory(null, mapAddr + pageSize, new byte[4000], 16, 2000, 2); break; case 2: - // testing Unsafe.copySwapMemory, trying to access next page after truncation. + // testing Unsafe.copySwapMemory, trying to access next page after truncation. unsafe.copySwapMemory(null, mapAddr + pageSize, null, allocMem, 2000, 2); break; + case 3: + MemorySegment segment = MemorySegment.ofBuffer(buffer); + // testing Unsafe.setMemory, trying to access next page after truncation. + segment.fill((byte) 0xF0); + break; } } diff --git a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java index 183b1c3afcf..b0d66ffe902 100644 --- a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java +++ b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java @@ -31,42 +31,37 @@ * @bug 8306583 */ - import jdk.test.lib.cds.CDSTestUtils; - import jdk.test.lib.process.OutputAnalyzer; - import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; - public class TestCDSVMCrash { +public class TestCDSVMCrash { - public static void main(String[] args) throws Exception { - if (args.length == 1) { - // This should guarantee to throw: - // java.lang.OutOfMemoryError: Requested array size exceeds VM limit - try { - Object[] oa = new Object[Integer.MAX_VALUE]; - throw new Error("OOME not triggered"); - } catch (OutOfMemoryError err) { - throw new Error("OOME didn't abort JVM!"); - } - } - // else this is the main test - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", - "-XX:-CreateCoredumpOnCrash", "-Xmx128m", "-Xshare:on", TestCDSVMCrash.class.getName(),"throwOOME"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - // executeAndLog should throw an exception in the VM crashed - try { + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + try { + Object[] oa = new Object[Integer.MAX_VALUE]; + throw new Error("OOME not triggered"); + } catch (OutOfMemoryError err) { + throw new Error("OOME didn't abort JVM!"); + } + } + // else this is the main test + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", + "-XX:-CreateCoredumpOnCrash", "-Xmx128m", + "-Xshare:on", TestCDSVMCrash.class.getName(), + "throwOOME"); + // executeAndLog should throw an exception in the VM crashed + try { CDSTestUtils.executeAndLog(pb, "cds_vm_crash"); throw new Error("Expected VM to crash"); - } catch(RuntimeException e) { + } catch(RuntimeException e) { if (!e.getMessage().equals("Hotspot crashed")) { - throw new Error("Expected message: Hotspot crashed"); + throw new Error("Expected message: Hotspot crashed"); } - } - int exitValue = output.getExitValue(); - if (0 == exitValue) { - //expecting a non zero value - throw new Error("Expected to get non zero exit value"); - } - output.shouldContain("A fatal error has been detected by the Java Runtime Environment"); + } System.out.println("PASSED"); - } - } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java index b9c2063f3e7..ef13a0a9414 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -199,6 +199,23 @@ public static void createModularJar(String jarPath, createJar(argList); } + public static void createModularJarWithManifest(String jarPath, + String classesDir, + String mainClass, + String manifest) throws Exception { + ArrayList argList = new ArrayList(); + argList.add("--create"); + argList.add("--file=" + jarPath); + if (mainClass != null) { + argList.add("--main-class=" + mainClass); + } + argList.add("--manifest=" + manifest); + argList.add("-C"); + argList.add(classesDir); + argList.add("."); + createJar(argList); + } + private static void createJar(ArrayList args) { if (DEBUG) printIterable("createJar args: ", args); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java new file mode 100644 index 00000000000..9e7579a34fd --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8322657 + * @summary This test defines an application module using the DefineModuleApp. + * When performing dynamic dump, the modular jar containing the module + * is in the -cp. The jar listed in the "Class-Path" attribute of the modular + * jar doesn't exist. VM should not crash during dynamic dump under this scenario. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @build jdk.test.whitebox.WhiteBox DefineModuleApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar define_module_app.jar DefineModuleApp + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. ModularJarWithNonExistentJar + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class ModularJarWithNonExistentJar extends DynamicArchiveTestBase { + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "../jigsaw/modulepath/src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path MANIFEST_PATH = Paths.get(TEST_SRC, "test-classes/manifest-with-non-existent-jar.txt"); + + // the module name of the test module + private static final String TEST_MODULE = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path modularJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + MODS_DIR.toString()); + + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + + modularJar = moduleDir.resolve(TEST_MODULE + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJarWithManifest(modularJar.toString(), classes, + MAIN_CLASS, MANIFEST_PATH.toString()); + } + + public static void main(String... args) throws Exception { + runTest(ModularJarWithNonExistentJar::testDefaultBase); + } + + static void testDefaultBase() throws Exception { + String topArchiveName = getNewArchiveName("top"); + doTest(topArchiveName); + } + + private static void doTest(String topArchiveName) throws Exception { + // compile the module and create the modular jar file + buildTestModule(); + String appJar = ClassFileInstaller.getJarPath("define_module_app.jar"); + dump(topArchiveName, + "-Xlog:cds,class+path=info", + "-Xlog:cds+dynamic=debug", + "-cp", appJar + File.pathSeparator + modularJar.toString(), + "DefineModuleApp", moduleDir.toString(), TEST_MODULE) + .assertNormalExit(output -> { + output.shouldContain("Written dynamic archive 0x"); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java index c55da54b5ab..88697496ac6 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java @@ -30,7 +30,7 @@ * @library /test/lib * @compile -source 1.8 -target 1.8 ../test-classes/HelloJDK8.java * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar Hello.jar HelloJDK8 - * @run driver TestAutoCreateSharedArchiveUpgrade + * @run driver/timeout=600 TestAutoCreateSharedArchiveUpgrade */ import java.io.File; @@ -52,7 +52,7 @@ public class TestAutoCreateSharedArchiveUpgrade { // the JDK using "jtreg -vmoption:-Dtest.previous.jdk=${JDK19_HOME} ..." private static final String PREV_JDK = System.getProperty("test.previous.jdk", null); - // If you're unning this test using something like + // If you're running this test using something like // "make test TEST=test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java", // the test.boot.jdk property is normally passed by make/RunTests.gmk private static String BOOT_JDK = System.getProperty("test.boot.jdk", null); @@ -103,8 +103,12 @@ static void setupJVMs(int fetchVersion) throws Throwable { newJVM = TEST_JDK + FS + "bin" + FS + "java"; + // Version 0 is used here to indicate that no version is supplied so that + // PREV_JDK or BOOT_JDK are used if (fetchVersion >= 19) { oldJVM = fetchJDK(fetchVersion) + FS + "bin" + FS + "java"; + } else if (fetchVersion > 0) { + throw new RuntimeException("Unsupported JDK version " + fetchVersion); } else if (PREV_JDK != null) { oldJVM = PREV_JDK + FS + "bin" + FS + "java"; } else if (BOOT_JDK != null) { @@ -187,6 +191,9 @@ private static String fetchJDK(int version) throws Throwable { case 20: build = 29; break; + case 21: + build = 35; + break; default: throw new RuntimeException("Unsupported JDK version " + version); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java new file mode 100644 index 00000000000..fad62598cc7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * This app defines a module using the ModuleLayer.defineModulesWithOneLoader API + * which calls the JVM_DefineModule. + **/ + +import java.nio.file.Path; +import java.lang.ModuleLayer.Controller; +import java.lang.module.*; +import java.util.List; +import java.util.Set; + +public class DefineModuleApp { + public static void main(String[] args) throws Throwable { + if (args.length != 2) { + throw new RuntimeException("DefineModuleApp expects 2 args but saw " + args.length); + } + final Path MODS = Path.of(args[0]); + final String MODULE_NAME = args[1]; + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(ModuleFinder.of(), ModuleFinder.of(MODS), Set.of(MODULE_NAME)); + ResolvedModule m = cf.findModule(MODULE_NAME).orElseThrow(); + ModuleLayer bootLayer = ModuleLayer.boot(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Controller controller = ModuleLayer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt new file mode 100644 index 00000000000..7558b8b2c82 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: NonExistent.jar +Created-By: 23-internal (Oracle Corporation) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java index eecc218a71a..aeb5696830d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java @@ -306,7 +306,7 @@ public static void runWithJarPath(String... extraRuntimeArgs) throws Exception { .shouldNotContain(OPTIMIZE_ENABLED) .shouldNotContain(OPTIMIZE_DISABLED); }); - tty("10. run with CDS on, with main/test jars on classpath also with -Xbootclasspath/a: should not pass"); + tty("10. run with CDS on, with main/test jars on classpath also with -Xbootclasspath/a: should pass"); TestCommon.run("-Xlog:cds", "-cp", mainJar.toString() + PATH_SEPARATOR + testJar.toString(), "-Xbootclasspath/a:", ".", @@ -314,9 +314,57 @@ public static void runWithJarPath(String... extraRuntimeArgs) throws Exception { .assertAbnormalExit(out -> { out.shouldNotContain(CLASS_FOUND_MESSAGE) .shouldNotContain(CLASS_NOT_FOUND_MESSAGE) - .shouldContain(OPTIMIZE_DISABLED) .shouldNotContain(OPTIMIZE_ENABLED) .shouldContain(MAP_FAILED); }); + + // Dump an archive with -Xbootclasspath/a + output = TestCommon.createArchive( + testJar.toString(), + appClasses, + "-Xbootclasspath/a:" + mainJar.toString()); + TestCommon.checkDump(output); + tty("11. run with CDS on, with test jar on classpath and with main jar on -Xbootclasspath/a: should pass"); + TestCommon.run("-Xlog:cds", + "-cp", testJar.toString(), + "-Xbootclasspath/a:" + mainJar.toString(), + MAIN_CLASS) + .assertNormalExit(out -> { + out.shouldNotContain(CLASS_FOUND_MESSAGE) + .shouldNotContain(CLASS_NOT_FOUND_MESSAGE) + .shouldContain(OPTIMIZE_ENABLED); + }); + tty("12. run with CDS on, with main jar on classpath and with test jar on -Xbootclasspath/a: should not pass due to class paths mismatch"); + TestCommon.run("-Xlog:cds", + "-cp", mainJar.toString(), + "-Xbootclasspath/a:" + testJar.toString(), + MAIN_CLASS) + .assertAbnormalExit(out -> { + out.shouldNotContain(CLASS_FOUND_MESSAGE) + .shouldNotContain(CLASS_NOT_FOUND_MESSAGE) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(MAP_FAILED); + }); + + // Skip the following test for dynamic CDS archive because the current + // dynamic dump test utililty does not support empty -cp with a classlist. + // (see createArchive(CDSOptions opts) in TestCommon.java) + if (!CDSTestUtils.isDynamicArchive()) { + // Dump an archive with only -Xbootclasspath/a + output = TestCommon.createArchive( + null, + appClasses, + "-Xbootclasspath/a:" + mainJar.toString()); + TestCommon.checkDump(output); + tty("13. run with CDS on, with the same -Xbootclasspath/a as dump time and adding a -cp with test.jar: should pass"); + TestCommon.run("-Xlog:cds,class+load", + "-cp", testJar.toString(), + "-Xbootclasspath/a:" + mainJar.toString(), + MAIN_CLASS) + .assertNormalExit(out -> { + out.shouldMatch(MAIN_FROM_CDS) + .shouldContain(OPTIMIZE_ENABLED); + }); + } } } diff --git a/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java b/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java index f7d50fd7fe6..71d984d3a63 100644 --- a/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java +++ b/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java @@ -47,7 +47,8 @@ public String[] getTests() { // CDS should not be disabled -- these critical classes cannot be replaced because // JvmtiExport::early_class_hook_env() is false. - "-subgraph java/lang/module/ResolvedModule jdk.internal.module.ArchivedModuleGraph", + "-subgraph java/lang/module/Configuration java.lang.module.Configuration", + "-subgraph java/lang/ModuleLayer java.lang.ModuleLayer", "-subgraph java/lang/Integer java.lang.Integer$IntegerCache", // Tests for archived full module graph. We cannot use whitebox, which requires appending to bootclasspath. diff --git a/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java b/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java index 06db9c07c73..4f59af310bf 100644 --- a/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java +++ b/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java @@ -42,7 +42,7 @@ public static void main(String... args) throws Exception { Path patches = Paths.get(System.getProperty("test.classes"), "patches", "java.base"); String syspaths = System.getProperty("sun.boot.library.path") + File.pathSeparator + System.getProperty("java.library.path"); - ProcessTools.executeTestJvm("-Dsun.boot.library.path=" + syspaths, + ProcessTools.executeTestJava("-Dsun.boot.library.path=" + syspaths, "--patch-module", "java.base=" + patches.toString(), "BootLoaderTest") .shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/runtime/jni/FindClassUtf8/FindClassUtf8.java b/test/hotspot/jtreg/runtime/jni/FindClassUtf8/FindClassUtf8.java index 4f90838c107..7b0a4cc46bf 100644 --- a/test/hotspot/jtreg/runtime/jni/FindClassUtf8/FindClassUtf8.java +++ b/test/hotspot/jtreg/runtime/jni/FindClassUtf8/FindClassUtf8.java @@ -43,10 +43,10 @@ public final class FindClassUtf8 { public static void main(String... args) throws Exception { if (args.length == 1) { // run java -Xcheck:jni FindClassUtf8 and check that the -Xcheck:jni message comes out. - ProcessTools.executeTestJvm("-Djava.library.path=" + Utils.TEST_NATIVE_PATH, - "-Xcheck:jni", - "-XX:-CreateCoredumpOnCrash", - "FindClassUtf8") + ProcessTools.executeTestJava("-Djava.library.path=" + Utils.TEST_NATIVE_PATH, + "-Xcheck:jni", + "-XX:-CreateCoredumpOnCrash", + "FindClassUtf8") .shouldContain("JNI class name is not a valid UTF8 string") .shouldNotHaveExitValue(0); // you get a core dump from -Xcheck:jni failures } else { diff --git a/test/hotspot/jtreg/runtime/jni/atExit/TestAtExit.java b/test/hotspot/jtreg/runtime/jni/atExit/TestAtExit.java index a54eaedbad4..82d834c869c 100644 --- a/test/hotspot/jtreg/runtime/jni/atExit/TestAtExit.java +++ b/test/hotspot/jtreg/runtime/jni/atExit/TestAtExit.java @@ -61,13 +61,13 @@ public static void main(String[] args) throws Exception { String jlp = "-Djava.library.path=" + Utils.TEST_NATIVE_PATH; // First run will terminate via DestroyJavaVM - OutputAnalyzer output = ProcessTools.executeTestJvm(jlp, main); + OutputAnalyzer output = ProcessTools.executeTestJava(jlp, main); output.shouldNotContain("Unexpected"); output.shouldHaveExitValue(0); output.reportDiagnosticSummary(); // Second run will terminate via System.exit() - output = ProcessTools.executeTestJvm(jlp, main, "doExit"); + output = ProcessTools.executeTestJava(jlp, main, "doExit"); output.shouldNotContain("Unexpected"); output.shouldHaveExitValue(0); output.reportDiagnosticSummary(); diff --git a/test/hotspot/jtreg/runtime/jni/checked/TestCheckedJniExceptionCheck.java b/test/hotspot/jtreg/runtime/jni/checked/TestCheckedJniExceptionCheck.java index e731bab6374..3c6efeb9a2d 100644 --- a/test/hotspot/jtreg/runtime/jni/checked/TestCheckedJniExceptionCheck.java +++ b/test/hotspot/jtreg/runtime/jni/checked/TestCheckedJniExceptionCheck.java @@ -205,9 +205,9 @@ public static void main(String[] args) throws Throwable { } // launch and check output - checkOuputForCorrectWarnings(ProcessTools.executeTestJvm("-Xcheck:jni", - "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, - "TestCheckedJniExceptionCheck")); + checkOuputForCorrectWarnings(ProcessTools.executeTestJava("-Xcheck:jni", + "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, + "TestCheckedJniExceptionCheck")); } } diff --git a/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java b/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java index 6395e3b9f0b..6bc09b8a034 100644 --- a/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java +++ b/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java @@ -45,7 +45,7 @@ public static void main(String[] args) throws Throwable { if (args == null || args.length == 0) { test(); } else { - // Uses executeProcess() instead of executeTestJvm() to avoid passing options + // Uses executeProcess() instead of executeTestJava() to avoid passing options // that might generate output on stderr (which should be empty for this test). ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xcheck:jni", diff --git a/test/hotspot/jtreg/runtime/jni/nativeStack/TestNativeStack.java b/test/hotspot/jtreg/runtime/jni/nativeStack/TestNativeStack.java index a7b8d945eec..d336097b8bd 100644 --- a/test/hotspot/jtreg/runtime/jni/nativeStack/TestNativeStack.java +++ b/test/hotspot/jtreg/runtime/jni/nativeStack/TestNativeStack.java @@ -51,19 +51,19 @@ public class TestNativeStack { public static void main(String[] args) throws Throwable { // case 1: Trigger a JNI warning with Xcheck:jni OutputAnalyzer oa = - ProcessTools.executeTestJvm("-Xcheck:jni", - "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, - "TestNativeStack$Main"); + ProcessTools.executeTestJava("-Xcheck:jni", + "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, + "TestNativeStack$Main"); oa.shouldHaveExitValue(0); oa.shouldContain("WARNING in native method"); oa.shouldContain("thread_start"); oa.reportDiagnosticSummary(); // Case 2: Trigger a JNI FatalError call - oa = ProcessTools.executeTestJvm("-XX:-CreateCoredumpOnCrash", - "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, - "TestNativeStack$Main", - "error"); + oa = ProcessTools.executeTestJava("-XX:-CreateCoredumpOnCrash", + "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, + "TestNativeStack$Main", + "error"); oa.shouldNotHaveExitValue(0); oa.shouldContain("FATAL ERROR in native method"); oa.shouldContain("thread_start"); diff --git a/test/hotspot/jtreg/runtime/jni/registerNativesWarning/TestRegisterNativesWarning.java b/test/hotspot/jtreg/runtime/jni/registerNativesWarning/TestRegisterNativesWarning.java index e22c75a6a44..e3d043ee4af 100644 --- a/test/hotspot/jtreg/runtime/jni/registerNativesWarning/TestRegisterNativesWarning.java +++ b/test/hotspot/jtreg/runtime/jni/registerNativesWarning/TestRegisterNativesWarning.java @@ -65,17 +65,17 @@ public static void main(String[] args) throws Exception { String cp = Utils.TEST_CLASS_PATH; String libp = Utils.TEST_NATIVE_PATH; - OutputAnalyzer output = ProcessTools.executeTestJvm("-Djava.library.path=" + libp, - Tester.class.getName()); + OutputAnalyzer output = ProcessTools.executeTestJava("-Djava.library.path=" + libp, + Tester.class.getName()); output.shouldContain(warning); output.shouldHaveExitValue(0); output.reportDiagnosticSummary(); // If we run everything from the "boot" loader there should be no warning - output = ProcessTools.executeTestJvm("-Djava.library.path=" + libp, - "-Xbootclasspath/a:" + cp, - "-Dsun.boot.library.path=" + libp, - Tester.class.getName()); + output = ProcessTools.executeTestJava("-Djava.library.path=" + libp, + "-Xbootclasspath/a:" + cp, + "-Dsun.boot.library.path=" + libp, + Tester.class.getName()); output.shouldNotContain(warning); output.shouldHaveExitValue(0); output.reportDiagnosticSummary(); diff --git a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java index e4ad27b46e5..a94d9af4c27 100644 --- a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java +++ b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java @@ -350,7 +350,7 @@ public RangeWithPageSize(String start, String end, String pageSize, String thpEl this.start = Long.parseUnsignedLong(start, 16); this.end = Long.parseUnsignedLong(end, 16); this.pageSize = Long.parseLong(pageSize); - this.thpEligible = Integer.parseInt(thpEligible) == 1; + this.thpEligible = thpEligible == null ? false : (Integer.parseInt(thpEligible) == 1); vmFlagHG = false; vmFlagHT = false; @@ -365,12 +365,11 @@ public RangeWithPageSize(String start, String end, String pageSize, String thpEl } } - // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false. - // Check the THPeligible property instead. - isTHP = !vmFlagHT && this.thpEligible; + // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false, + // therefore also check thpEligible. If this is still causing problems in the future, + // we might have to check the AnonHugePages field. - // vmFlagHG should imply isTHP - assert !vmFlagHG || isTHP; + isTHP = vmFlagHG || this.thpEligible; } public long getPageSize() { diff --git a/test/hotspot/jtreg/runtime/stringtable/StringTableCleaningTest.java b/test/hotspot/jtreg/runtime/stringtable/StringTableCleaningTest.java index 4c54273c8c7..a62d61166fc 100644 --- a/test/hotspot/jtreg/runtime/stringtable/StringTableCleaningTest.java +++ b/test/hotspot/jtreg/runtime/stringtable/StringTableCleaningTest.java @@ -58,7 +58,7 @@ public static void main(String[] args) throws Exception { subargs.addAll(List.of("-Xlog:gc,gc+start,stringtable*=trace", "-Xmx1g")); subargs.add(Tester.class.getName()); subargs.addAll(Arrays.asList(args)); - OutputAnalyzer output = ProcessTools.executeTestJvm(subargs); + OutputAnalyzer output = ProcessTools.executeTestJava(subargs); output.shouldHaveExitValue(0); checkOutput(output); } diff --git a/test/hotspot/jtreg/sanity/BasicVMTest.java b/test/hotspot/jtreg/sanity/BasicVMTest.java index a128cdfea37..47773d63df4 100644 --- a/test/hotspot/jtreg/sanity/BasicVMTest.java +++ b/test/hotspot/jtreg/sanity/BasicVMTest.java @@ -42,7 +42,7 @@ public static void main(String[] args) throws Exception { "-X", "-help"); for (String flag : flags) { - ProcessTools.executeTestJvm(flag) + ProcessTools.executeTestJava(flag) .shouldHaveExitValue(0); } } diff --git a/test/jdk/java/util/zip/ZipFile/GetDirEntry.java b/test/hotspot/jtreg/serviceability/HeapDump/FullGCHeapDumpLimitTest.java similarity index 58% rename from test/jdk/java/util/zip/ZipFile/GetDirEntry.java rename to test/hotspot/jtreg/serviceability/HeapDump/FullGCHeapDumpLimitTest.java index e74fa6b3154..c44fea3e10b 100644 --- a/test/jdk/java/util/zip/ZipFile/GetDirEntry.java +++ b/test/hotspot/jtreg/serviceability/HeapDump/FullGCHeapDumpLimitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024 Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,23 +21,23 @@ * questions. */ -/* @test - @bug 4206838 - @summary getEntry() will search for a directory - even without an ending '/'. +/** + * @test + * @requires vm.gc.Serial & (vm.opt.DisableExplicitGC != "true") + * @summary Test of option -XX:FullGCHeapDumpLimit + * @library /test/lib + * @run main/othervm -XX:+UseSerialGC -XX:+HeapDumpBeforeFullGC -XX:+HeapDumpAfterFullGC -XX:HeapDumpPath=test.hprof -XX:FullGCHeapDumpLimit=1 FullGCHeapDumpLimitTest */ -import java.io.*; -import java.util.zip.*; +import java.io.File; -public class GetDirEntry { - public static void main(String args[]) throws Exception { - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), - "input.jar"))) { - ZipEntry ze = zf.getEntry("META-INF"); - if (ze == null) { - throw new Exception("failed to find a directory entry"); - } - } +import jdk.test.lib.Asserts; + +public class FullGCHeapDumpLimitTest { + + public static void main(String[] args) throws Exception { + System.gc(); + Asserts.assertTrue(new File("test.hprof").exists()); + Asserts.assertFalse(new File("test.hprof.1").exists()); } } diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java index f4da5e979e3..ef05468bc29 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Arm Limited. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Arm Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -58,15 +59,12 @@ public class PerfMapTest { static final Pattern LINE_PATTERN = Pattern.compile("^((?:0x)?\\p{XDigit}+)\\s+((?:0x)?\\p{XDigit}+)\\s+(.*)$"); - public void run(CommandExecutor executor) { - OutputAnalyzer output = executor.execute("Compiler.perfmap"); + public void run(CommandExecutor executor, String cmd, Path path) { + OutputAnalyzer output = executor.execute(cmd); output.stderrShouldBeEmpty(); output.stdoutShouldBeEmpty(); - final long pid = ProcessHandle.current().pid(); - final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid)); - Assert.assertTrue(Files.exists(path)); // Sanity check the file contents @@ -81,7 +79,19 @@ public void run(CommandExecutor executor) { } @Test - public void jmx() { - run(new JMXExecutor()); + public void defaultMapFile() { + final long pid = ProcessHandle.current().pid(); + final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid)); + run(new JMXExecutor(), "Compiler.perfmap", path); + } + + @Test + public void specifiedMapFile() { + String test_dir = System.getProperty("test.dir", "."); + Path path = null; + do { + path = Paths.get(String.format("%s/%s.map", test_dir, UUID.randomUUID().toString())); + } while(Files.exists(path)); + run(new JMXExecutor(), "Compiler.perfmap " + path.toString(), path); } } diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java index 2ea09dd1597..0010c5bdd78 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java @@ -66,7 +66,6 @@ private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File appOut.shouldContain("Merge heap files complete"); } else { appOut.shouldNotContain("Dump heap objects in parallel"); - appOut.shouldNotContain("Merge heap files complete"); } HprofParser.parseAndVerify(heapDumpFile); diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestLambdaFormRetransformation.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestLambdaFormRetransformation.java index feacea07aab..48c9ad1328e 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestLambdaFormRetransformation.java +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestLambdaFormRetransformation.java @@ -60,7 +60,7 @@ public class TestLambdaFormRetransformation { public static void main(String args[]) throws Throwable { Path agent = TestLambdaFormRetransformation.buildAgent(); - OutputAnalyzer oa = ProcessTools.executeTestJvm("-javaagent:" + + OutputAnalyzer oa = ProcessTools.executeTestJava("-javaagent:" + agent.toAbsolutePath().toString(), "-version"); oa.shouldHaveExitValue(ExitCode.OK.value); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestRedefineWithUnresolvedClass.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestRedefineWithUnresolvedClass.java index 2e36e33ce83..4bcd2a44588 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestRedefineWithUnresolvedClass.java +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/TestRedefineWithUnresolvedClass.java @@ -79,7 +79,7 @@ private static void buildJar(String jarName) throws Throwable { } private static void launchTest() throws Throwable { - OutputAnalyzer output = ProcessTools.executeTestJvm( + OutputAnalyzer output = ProcessTools.executeTestJava( "-javaagent:" + testClasses + "UnresolvedClassAgent.jar", "-Dtest.classes=" + testClasses, "UnresolvedClassAgent"); diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java index 17c17b9b1f5..4ee1d1a0bfc 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java @@ -25,20 +25,22 @@ * @test id=default * @bug 8312498 * @summary Basic test for JVMTI GetThreadState with virtual threads + * @library /test/lib * @run junit/othervm/native GetThreadStateTest */ /* * @test id=no-vmcontinuations * @requires vm.continuations + * @library /test/lib * @run junit/othervm/native -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations GetThreadStateTest */ import java.util.StringJoiner; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; +import jdk.test.lib.thread.VThreadPinner; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -75,10 +77,10 @@ void testTerminated() throws Exception { */ @Test void testRunnable() throws Exception { - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); var done = new AtomicBoolean(); var thread = Thread.ofVirtual().start(() -> { - latch.countDown(); + started.set(true); // spin until done while (!done.get()) { @@ -87,7 +89,7 @@ void testRunnable() throws Exception { }); try { // wait for thread to start execution - latch.await(); + awaitTrue(started); // thread should be runnable int expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_RUNNABLE; @@ -107,17 +109,17 @@ void testRunnable() throws Exception { */ @Test void testMonitorEnter() throws Exception { - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); Object lock = new Object(); var thread = Thread.ofVirtual().unstarted(() -> { - latch.countDown(); + started.set(true); synchronized (lock) { } }); try { synchronized (lock) { // start thread and wait for it to start execution thread.start(); - latch.await(); + awaitTrue(started); // thread should block on monitor enter int expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; @@ -137,19 +139,19 @@ void testMonitorEnter() throws Exception { */ @Test void testObjectWait() throws Exception { - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); Object lock = new Object(); var thread = Thread.ofVirtual().start(() -> { synchronized (lock) { - latch.countDown(); + started.set(true); try { lock.wait(); } catch (InterruptedException e) { } } }); try { - // wait for thread to own monitor - latch.await(); + // wait for thread to start execution + awaitTrue(started); // thread should wait int expected = JVMTI_THREAD_STATE_ALIVE | @@ -179,19 +181,19 @@ void testObjectWait() throws Exception { */ @Test void testObjectWaitMillis() throws Exception { - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); Object lock = new Object(); var thread = Thread.ofVirtual().start(() -> { synchronized (lock) { - latch.countDown(); + started.set(true); try { lock.wait(Long.MAX_VALUE); } catch (InterruptedException e) { } } }); try { - // wait for thread to own monitor - latch.await(); + // wait for thread to start execution + awaitTrue(started); // thread should wait int expected = JVMTI_THREAD_STATE_ALIVE | @@ -221,17 +223,17 @@ void testObjectWaitMillis() throws Exception { */ @Test void testPark() throws Exception { - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); var done = new AtomicBoolean(); var thread = Thread.ofVirtual().start(() -> { - latch.countDown(); + started.set(true); while (!done.get()) { LockSupport.park(); } }); try { // wait for thread to start execution - latch.await(); + awaitTrue(started); // thread should park int expected = JVMTI_THREAD_STATE_ALIVE | @@ -251,17 +253,17 @@ void testPark() throws Exception { */ @Test void testParkNanos() throws Exception { - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); var done = new AtomicBoolean(); var thread = Thread.ofVirtual().start(() -> { - latch.countDown(); + started.set(true); while (!done.get()) { LockSupport.parkNanos(Long.MAX_VALUE); } }); try { // wait for thread to start execution - latch.await(); + awaitTrue(started); // thread should park int expected = JVMTI_THREAD_STATE_ALIVE | @@ -281,20 +283,19 @@ void testParkNanos() throws Exception { */ @Test void testParkWhenPinned() throws Exception { - var latch = new CountDownLatch(1); - Object lock = new Object(); + var started = new AtomicBoolean(); var done = new AtomicBoolean(); var thread = Thread.ofVirtual().start(() -> { - synchronized (lock) { - latch.countDown(); + VThreadPinner.runPinned(() -> { + started.set(true); while (!done.get()) { LockSupport.park(); } - } + }); }); try { - // wait for thread to own monitor - latch.await(); + // wait for thread to start execution + awaitTrue(started); // thread should park int expected = JVMTI_THREAD_STATE_ALIVE | @@ -314,20 +315,19 @@ void testParkWhenPinned() throws Exception { */ @Test void testParkNanosWhenPinned() throws Exception { - var latch = new CountDownLatch(1); - Object lock = new Object(); + var started = new AtomicBoolean(); var done = new AtomicBoolean(); var thread = Thread.ofVirtual().start(() -> { - synchronized (lock) { - latch.countDown(); + VThreadPinner.runPinned(() -> { + started.set(true); while (!done.get()) { LockSupport.parkNanos(Long.MAX_VALUE); } - } + }); }); try { - // wait for thread to own monitor - latch.await(); + // wait for thread to start execution + awaitTrue(started); // thread should park int expected = JVMTI_THREAD_STATE_ALIVE | @@ -342,6 +342,15 @@ void testParkNanosWhenPinned() throws Exception { } } + /** + * Waits for the boolean value to become true. + */ + private static void awaitTrue(AtomicBoolean ref) throws Exception { + while (!ref.get()) { + Thread.sleep(20); + } + } + /** * Asserts that the given thread has the expected JVMTI state. */ diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java index 89a9a0514bf..2243a1d37b6 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -183,6 +185,7 @@ private static void createDump(File dumpFile, String[] extraOptions) throws Exce List extraVMArgs = new ArrayList<>(); extraVMArgs.add("-Djdk.virtualThreadScheduler.parallelism=1"); + extraVMArgs.add("-Xlog:heapdump"); extraVMArgs.addAll(Arrays.asList(extraOptions)); LingeredApp.startApp(theApp, extraVMArgs.toArray(new String[0])); @@ -222,11 +225,22 @@ private static void verifyDump(File dumpFile) throws Exception { // Log all threads with stack traces and stack references. List threads = snapshot.getThreads(); List roots = Collections.list(snapshot.getRoots()); + // And detect thread object duplicates. + Set uniqueThreads = new HashSet<>(); + log("Threads:"); for (ThreadObject thread: threads) { + JavaHeapObject threadObj = snapshot.findThing(thread.getId()); + JavaClass threadClass = threadObj.getClazz(); StackTrace st = thread.getStackTrace(); StackFrame[] frames = st.getFrames(); - log("thread " + thread.getIdString() + ", " + frames.length + " frames"); + log("thread " + thread.getIdString() + " (" + threadClass.getName() + "), " + frames.length + " frames"); + + if (uniqueThreads.contains(thread.getId())) { + log(" - ERROR: duplicate"); + } else { + uniqueThreads.add(thread.getId()); + } List stackRoots = findStackRoot(roots, thread); for (int i = 0; i < frames.length; i++) { @@ -249,11 +263,14 @@ private static void verifyDump(File dumpFile) throws Exception { } } + if (threads.size() != uniqueThreads.size()) { + throw new RuntimeException("Thread duplicates detected (" + (threads.size() - uniqueThreads.size()) + ")"); + } + // Verify objects from thread stacks are dumped. test(snapshot, VThreadInHeapDumpTarg.VThreadMountedReferenced.class); test(snapshot, VThreadInHeapDumpTarg.PThreadReferenced.class); - // Dumping of unmounted vthreads is not implemented yet - //test(snapshot, VThreadInHeapDumpTarg.VThreadUnmountedReferenced.class); + test(snapshot, VThreadInHeapDumpTarg.VThreadUnmountedReferenced.class); } } diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java new file mode 100644 index 00000000000..d679f382d93 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test id=default + * @summary Do not suspend virtual threads in a critical section. + * @bug 8311218 + * @requires vm.continuations + * @library /testlibrary + * @run main/othervm SuspendWithInterruptLock + */ + +/** + * @test id=xint + * @summary Do not suspend virtual threads in a critical section. + * @bug 8311218 + * @requires vm.continuations + * @library /testlibrary + * @run main/othervm -Xint SuspendWithInterruptLock + */ + +import jvmti.JVMTIUtils; + +public class SuspendWithInterruptLock { + static volatile boolean done; + + public static void main(String[] args) throws Exception { + Thread yielder = Thread.ofVirtual().name("yielder").start(() -> yielder()); + Thread stateReader = Thread.ofVirtual().name("stateReader").start(() -> stateReader(yielder)); + Thread suspender = new Thread(() -> suspender(stateReader)); + suspender.start(); + + yielder.join(); + stateReader.join(); + suspender.join(); + } + + static private void yielder() { + int iterations = 100_000; + while (iterations-- > 0) { + Thread.yield(); + } + done = true; + } + + static private void stateReader(Thread target) { + while (!done) { + target.getState(); + } + } + + static private void suspender(Thread target) { + while (!done) { + suspendThread(target); + sleep(1); + resumeThread(target); + // Allow progress + sleep(5); + } + } + + static void suspendThread(Thread t) { + try { + JVMTIUtils.suspendThread(t); + } catch (JVMTIUtils.JvmtiException e) { + if (e.getCode() != JVMTIUtils.JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw e; + } + } + } + + static void resumeThread(Thread t) { + try { + JVMTIUtils.resumeThread(t); + } catch (JVMTIUtils.JvmtiException e) { + if (e.getCode() != JVMTIUtils.JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw e; + } + } + } + + static private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} + diff --git a/test/hotspot/jtreg/testlibrary/ctw/Makefile b/test/hotspot/jtreg/testlibrary/ctw/Makefile index 5ba3bbb659a..b67500d0c5e 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/Makefile +++ b/test/hotspot/jtreg/testlibrary/ctw/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -42,21 +42,18 @@ JAVAC = $(JDK_HOME)/bin/javac JAR = $(JDK_HOME)/bin/jar SRC_FILES = $(shell find $(SRC_DIR) -name '*.java') -LIB_FILES = $(shell find $(TESTLIBRARY_DIR)/jdk/test/lib/ \ +# Exclude files that need '--enable-preview' to compile. +LIB_FILES = $(filter-out %ModuleInfoWriter.java, $(shell find $(TESTLIBRARY_DIR)/jdk/test/lib/ \ $(TESTLIBRARY_DIR)/jdk/test/lib/process \ $(TESTLIBRARY_DIR)/jdk/test/lib/util \ $(TESTLIBRARY_DIR)/jtreg \ - -maxdepth 1 -name '*.java') + -maxdepth 1 -name '*.java')) WB_SRC_FILES = $(shell find $(TESTLIBRARY_DIR)/jdk/test/lib/compiler $(TESTLIBRARY_DIR)/jdk/test/whitebox -name '*.java') WB_CLASS_FILES := $(subst $(TESTLIBRARY_DIR)/,,$(WB_SRC_FILES)) WB_CLASS_FILES := $(patsubst %.java,%.class,$(WB_CLASS_FILES)) EXPORTS=--add-exports java.base/jdk.internal.jimage=ALL-UNNAMED \ --add-exports java.base/jdk.internal.misc=ALL-UNNAMED \ - --add-exports java.base/jdk.internal.module=ALL-UNNAMED \ --add-exports java.base/jdk.internal.reflect=ALL-UNNAMED \ - --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED \ - --add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \ - --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED \ --add-exports java.base/jdk.internal.access=ALL-UNNAMED CTW_MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSafepointWhilePrinting.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSafepointWhilePrinting.java deleted file mode 100644 index 99de3c1510c..00000000000 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSafepointWhilePrinting.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package compiler.testlibrary_tests.ir_framework.tests; - -import compiler.lib.ir_framework.CompilePhase; -import compiler.lib.ir_framework.IR; -import compiler.lib.ir_framework.IRNode; -import compiler.lib.ir_framework.Test; -import compiler.lib.ir_framework.driver.irmatching.IRMatcher; -import compiler.lib.ir_framework.driver.irmatching.Matchable; -import compiler.lib.ir_framework.driver.irmatching.parser.TestClassParser; -import jdk.test.lib.Utils; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; - -/* - * @test - * @bug 8300273 - * @requires vm.debug == true & vm.flagless - * @summary Test TestClassParser such that it correctly parses the hotspot_pid* files with safepoint interruption messages - * @library /test/lib /testlibrary_tests / - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run junit/othervm -Xbootclasspath/a:. -DSkipWhiteBoxInstall=true -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI compiler.testlibrary_tests.ir_framework.tests.TestSafepointWhilePrinting - */ -public class TestSafepointWhilePrinting { - static int iFld; - - @org.junit.Test - public void test() throws IOException { - String hotspotPidFileName = "safepoint_while_printing_hotspot_pid.log"; - Path hotspotPidFilePath = Paths.get(Utils.TEST_SRC).resolve(hotspotPidFileName); - // Copy file to current workdir - Files.copy(hotspotPidFilePath, Paths.get("").resolve(hotspotPidFileName), - StandardCopyOption.REPLACE_EXISTING); - - String irEncoding = - """ - ##### IRMatchRulesEncoding - used by TestFramework ##### - ,{comma separated applied @IR rule ids} - test1,1 - test2,1 - testSafepointInBlock,1 - testQueueInBlock1,1 - testQueueInBlock2,1 - testDoubleInterruptOuter,1 - testDoubleInterruptMiddle,1 - testDoubleInterruptInner,1 - testCompilePhaseBackToBackFirst,1 - testCompilePhaseBackToBackLast,1 - ----- END ----- - ##### IRMatchingVMInfo - used by TestFramework ##### - : - cpuFeatures:empty_cpu_info - MaxVectorSize:64 - MaxVectorSizeIsDefault:1 - LoopMaxUnroll:64 - UseAVX:1 - UseAVXIsDefault:1 - ----- END VMInfo ----- - """; - TestClassParser testClassParser = new TestClassParser(TestSafepointWhilePrinting.class); - Matchable testClassMatchable = testClassParser.parse(hotspotPidFileName, irEncoding); - IRMatcher matcher = new IRMatcher(testClassMatchable); - matcher.match(); - } - - @Test - @IR(counts = {IRNode.CMP_UL3, "1"}) - public void test1() { - iFld = 34; - } - - @Test - @IR(counts = {IRNode.CMP_UL3, "1"}) - public void test2() { - iFld = 34; - } - - @Test - @IR(counts = {"testSafepointInBlock @ bci:-1", "1"}, phase = CompilePhase.PRINT_IDEAL) - public void testSafepointInBlock() { - iFld = 34; - } - - @Test - @IR(counts = {"testQueueInBlock1 @ bci:-1", "1"}, phase = CompilePhase.PRINT_IDEAL) - public void testQueueInBlock1() { - iFld = 34; - } - - @Test - @IR(counts = {"testQueueInBlock2 @ bci:-1", "1"}, phase = CompilePhase.PRINT_IDEAL) - public void testQueueInBlock2() { - iFld = 34; - } - @Test - @IR(counts = {"!jvms: TestSafepointWhilePrinting::testDoubleInterruptOuter", "1"}, phase = CompilePhase.PRINT_IDEAL) - public void testDoubleInterruptOuter() { - iFld = 34; - } - - @Test - @IR(counts = {"testDoubleInterruptMiddle @ bci:-1", "1", IRNode.CMP_UL3, "1"}, phase = CompilePhase.PRINT_IDEAL) - public void testDoubleInterruptMiddle() { - iFld = 34; - } - - @Test - @IR(counts = {IRNode.CON_L, "1"}, phase = CompilePhase.PRINT_IDEAL) - public void testDoubleInterruptInner() { - iFld = 34; - } - - @Test - @IR(counts = {"(line 115)", "1", IRNode.CMP_UL3, "1"}, phase = {CompilePhase.AFTER_PARSING, CompilePhase.BEFORE_MATCHING}) - public void testCompilePhaseBackToBackFirst() { - iFld = 34; - } - - @Test - @IR(counts = {"(line 115)", "1", IRNode.CMP_UL3, "1"}, phase = {CompilePhase.AFTER_PARSING, CompilePhase.BEFORE_MATCHING}) - public void testCompilePhaseBackToBackLast() { - iFld = 34; - } -} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/safepoint_while_printing_hotspot_pid.log b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/safepoint_while_printing_hotspot_pid.log deleted file mode 100644 index 2bdd2540f08..00000000000 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/safepoint_while_printing_hotspot_pid.log +++ /dev/null @@ -1,163 +0,0 @@ - - 1682 967 b 3 jdk.test.lib.Asserts::assertEquals (7 bytes) - - - - - - - - - - 1716 995 3 compiler.testlibrary_tests.ir_framework.tests.TestSafepointWhilePrinting::compareLongWithImm5 (8 bytes) made not entrant - - 1716 1018 b 4 compiler.testlibrary_tests.ir_framework.tests.TestSafepointWhilePrinting::test1 (8 bytes) - - - - 1716 1008 b 3 java.util.Arrays::copyOfRange (90 bytes) - - 1716 1013 b 4 compiler.testlibrary_tests.ir_framework.tests.TestSafepointWhilePrinting::test2 (8 bytes) - - - - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 3 Start === 3 0 [[ 3 5 6 7 8 9 11 ]] #{0:control, 1:abIO, 2:memory, 3:rawptr:BotPTR, 4:return_address, 5:compiler/intrinsics/TestSafepointWhilePrinting:NotNull *, 6:long, 7:half} - 5 Parm === 3 [[ 26 ]] Control !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 6 Parm === 3 [[ 26 ]] I_O !jvms: - - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 3 Start === 3 0 [[ 3 5 6 7 8 9 11 ]] #{0:control, 1:abIO, 2:memory, 3:rawptr:BotPTR, 4:return_address, 5:compiler/intrinsics/TestSafepointWhilePrinting:NotNull *, 6:long, 7:half} - 5 Parm === 3 [[ 26 ]] Control !jvms: TestSafepointWhilePrinting::test2 @ bci:-1 (line 109) - 6 Parm === 3 [[ 26 ]] I_O !jvms: TestSafepointWhilePrinting::test2 @ bci:-1 (line 109) - 7 Parm === 3 [[ 26 ]] Memory Memory: @BotPTR *+bot, idx=Bot; !jvms: TestSafepointWhilePrinting::test2 @ bci:-1 (line 109) - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::test2 @ bci:-1 (line 109) - 9 Parm === 3 [[ 26 ]] ReturnAdr !jvms: TestSafepointWhilePrinting::test2 @ bci:-1 (line 109) - 11 Parm === 3 [[ 25 ]] Parm1: long !jvms: TestSafepointWhilePrinting::test2 @ bci:-1 (line 109) - 24 ConL === 0 [[ 25 ]] #long:42 - 25 CmpUL3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test2 @ bci:4 (line 109) - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - - TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 7 Parm === 3 [[ 26 ]] Memory Memory: @BotPTR *+bot, idx=Bot; !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 9 Parm === 3 [[ 26 ]] ReturnAdr !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 11 Parm === 3 [[ 25 ]] Parm1: long !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 24 ConL === 0 [[ 25 ]] #long:172032 - 25 CmpUL3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test1 @ bci:4 (line 115) - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - - - - 1784 993 3 compiler.intrinsics.TestCompareUnsigned::compareLongWithImm3 (8 bytes) made not entrant - 1784 1013 b 4 compiler.intrinsics.TestCompareUnsigned::compareLongWithImm1 (8 bytes) - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::testSafepointInBlock - @ bci:-1 (line 109) - 24 ConL === 0 [[ 25 ]] #long:42 - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - - - - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::testQueueInBlock1 - - - - @ bci:-1 (line 109) - 24 ConL === 0 [[ 25 ]] #long:42 - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::testQueueInBlock2 - @ bci:-1 (line 109) - 24 ConL === 0 [[ 25 ]] #long:42 - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - - - - - - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 3 Start === 3 0 [[ 3 5 6 7 8 9 11 ]] #{0:control, 1:abIO, 2:memory, 3:rawptr:BotPTR, 4:return_address, 5:compiler/intrinsics/TestSafepointWhilePrinting:NotNull *, 6:long, 7:half} - 6 Parm === 3 [[ 26 ]] I_O !jvms: - - -AFTER: print_ideal - 0 Root === 0 26 [[ 0 1 3 24 ]] inner - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::testDoubleInterruptMiddle - @ bci:-1 (line 109) - 25 Cmp - - - - - 24 ConL === 0 [[ 25 ]] #long:42 - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - -UL3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test2 @ bci:4 (line 109) - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - - TestSafepointWhilePrinting::testDoubleInterruptOuter @ bci:-1 (line 115) - 7 Parm === 3 [[ 26 ]] Memory Memory: @BotPTR *+bot, idx=Bot; !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 8 Parm === 3 [[ 26 ]] FramePtr !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 9 Parm === 3 [[ 26 ]] ReturnAdr !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 11 Parm === 3 [[ 25 ]] Parm1: long !jvms: TestSafepointWhilePrinting::test1 @ bci:-1 (line 115) - 24 ConL === 0 [[ 25 ]] #long:172032 - 25 CmpUL3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test1 @ bci:4 (line 115) - 26 Return === 5 6 7 8 9 returns 25 [[ 0 ]] - - - - - - 24 ConL === 0 [[ 25 ]] #long:172032 - 25 CmpUL - - - - 24 ConL === 0 [[ 25 ]] #long:172032 - 25 CmpUL3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test1 @ bci:4 (line 115) - - - 24 ConL === 0 [[ 25 ]] #long:172032 - 25 CmpU - -3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test1 @ bci:4 ( - -L3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test1 @ bci:4 (line - -line 115) - - - - - - 24 ConL === 0 [[ 25 ]] #long:172032 - 25 CmpU - -115) - - -L3 === _ 11 24 [[ 26 ]] !jvms: TestSafepointWhilePrinting::test1 @ bci:4 (line 115) - \ No newline at end of file diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Agent_OnUnload/agentonunload001/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Agent_OnUnload/agentonunload001/TestDriver.java index 9d8bb71cbc5..48245698712 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Agent_OnUnload/agentonunload001/TestDriver.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Agent_OnUnload/agentonunload001/TestDriver.java @@ -53,7 +53,7 @@ public class TestDriver { public static void main(String[] args) throws Exception { - OutputAnalyzer oa = ProcessTools.executeTestJvm( + OutputAnalyzer oa = ProcessTools.executeTestJava( "-agentlib:agentonunload001=-waittime=5", nsk.jvmti.Agent_OnUnload.agentonunload001.class.getName()); oa.shouldHaveExitValue(95); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/general_functions/GF08/gf08t.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/general_functions/GF08/gf08t.java index 9f028153342..964283d2b01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/general_functions/GF08/gf08t.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/general_functions/GF08/gf08t.java @@ -38,13 +38,13 @@ public static void main(String[] args) throws Exception { .skip(3) .collect(Collectors.joining(" ")); - OutputAnalyzer oa = ProcessTools.executeTestJvm( + OutputAnalyzer oa = ProcessTools.executeTestJava( "-agentlib:" + libName + "=-waittime=5 setVerboseMode=yes", className); oa.shouldHaveExitValue(95); oa.stdoutShouldContain(phrase); - oa = ProcessTools.executeTestJvm( + oa = ProcessTools.executeTestJava( "-agentlib:" + libName + "=-waittime=5 setVerboseMode=no", "-verbose:" + verboseType, className); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA02/ma02t001/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA02/ma02t001/TestDriver.java index 2aae25104fe..3d474c4e149 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA02/ma02t001/TestDriver.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA02/ma02t001/TestDriver.java @@ -47,7 +47,7 @@ public class TestDriver { public static void main(String[] args) throws Exception { - OutputAnalyzer oa = ProcessTools.executeTestJvm( + OutputAnalyzer oa = ProcessTools.executeTestJava( "-agentlib:ma02t001=-waittime=5", "-agentlib:ma02t001a=-waittime=5", nsk.jvmti.scenarios.multienv.MA02.ma02t001.class.getName()); diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java new file mode 100644 index 00000000000..14215004937 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package common.dtd; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.xml.sax.XMLReader; + +/* + * @test + * @bug 8322214 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng common.dtd.DTDPropertiesTest + * @summary Verifies the getProperty function on DTD properties works the same + * as before the property 'jdk.xml.dtd.support' was introduced. + */ +public class DTDPropertiesTest { + // Xerces Property + public static final String DISALLOW_DTD = "http://apache.org/xml/features/disallow-doctype-decl"; + + /* + * DataProvider for verifying Xerces' disallow-DTD feature + * Fields: property name, setting (null indicates not specified), expected + */ + @DataProvider(name = "XercesProperty") + public Object[][] getXercesProperty() throws Exception { + return new Object[][] { + { DISALLOW_DTD, null, false}, + { DISALLOW_DTD, true, true}, + { DISALLOW_DTD, false, false}, + }; + } + + /* + * DataProvider for verifying StAX's supportDTD feature + * Fields: property name, setting (null indicates not specified), expected + */ + @DataProvider(name = "StAXProperty") + public Object[][] getStAXProperty() throws Exception { + return new Object[][] { + { XMLInputFactory.SUPPORT_DTD, null, true}, + { XMLInputFactory.SUPPORT_DTD, true, true}, + { XMLInputFactory.SUPPORT_DTD, false, false}, + }; + } + + /** + * Verifies the disallow DTD feature with SAX. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "XercesProperty") + public void testSAX(String name, Boolean setting, Boolean expected) throws Exception { + SAXParserFactory spf = SAXParserFactory.newDefaultInstance(); + if (setting != null) { + spf.setFeature(name, setting); + } + Assert.assertEquals((Boolean)spf.getFeature(name), expected); + System.out.println(spf.getFeature(name)); + + + SAXParser saxParser = spf.newSAXParser(); + XMLReader reader = saxParser.getXMLReader(); + Assert.assertEquals((Boolean)reader.getFeature(name), expected); + System.out.println(reader.getFeature(name)); + } + + /** + * Verifies the disallow DTD feature with DOM. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "XercesProperty") + public void testDOM(String name, Boolean setting, Boolean expected) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + if (setting != null) { + dbf.setFeature(name, setting); + } + Assert.assertEquals((Boolean)dbf.getFeature(name), expected); + System.out.println(dbf.getFeature(name)); + } + + /** + * Verifies the StAX's supportDTD feature. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "StAXProperty") + public void testStAX(String name, Boolean setting, Boolean expected) throws Exception { + XMLInputFactory xif = XMLInputFactory.newInstance(); + if (setting != null) { + xif.setProperty(name, setting); + } + Assert.assertEquals((Boolean)xif.getProperty(name), expected); + System.out.println((Boolean)xif.getProperty(name)); + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/stream/XMLStreamExceptionTest/ExceptionCauseTest.java b/test/jaxp/javax/xml/jaxp/unittest/stream/XMLStreamExceptionTest/ExceptionCauseTest.java new file mode 100644 index 00000000000..e32527621f8 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/stream/XMLStreamExceptionTest/ExceptionCauseTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package stream.XMLStreamExceptionTest; + +import java.io.IOException; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + +import org.testng.Assert; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/* + * @test + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow stream.XMLStreamExceptionTest.ExceptionCauseTest + * @run testng/othervm stream.XMLStreamExceptionTest.ExceptionCauseTest + * @summary Test XMLStreamException constructor initializes chained exception + */ +@Listeners({jaxp.library.BasePolicy.class}) +public class ExceptionCauseTest { + + @Test + public void testExceptionCause() { + + // Create exception with cause + Throwable cause = new Throwable("cause"); + Location location = new Location() { + public int getLineNumber() { return 0; } + public int getColumnNumber() { return 0; } + public int getCharacterOffset() { return 0; } + public String getPublicId() { return null; } + public String getSystemId() { return null; } + }; + XMLStreamException e = new XMLStreamException("message", location, cause); + + // Verify cause + Assert.assertSame(e.getCause(), cause, "XMLStreamException has the wrong cause"); + } +} diff --git a/test/jdk/ProblemList-generational-zgc.txt b/test/jdk/ProblemList-generational-zgc.txt index d6a6f63c6a5..9fa9874d20c 100644 --- a/test/jdk/ProblemList-generational-zgc.txt +++ b/test/jdk/ProblemList-generational-zgc.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # 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,4 +38,3 @@ sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8307393 generic-all sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8307393 generic-all com/sun/jdi/ThreadMemoryLeakTest.java 8307402 generic-all -java/util/concurrent/locks/Lock/OOMEInAQS.java 8309218 generic-all diff --git a/test/jdk/ProblemList-zgc.txt b/test/jdk/ProblemList-zgc.txt index df7edd2cf7d..9fae070e25d 100644 --- a/test/jdk/ProblemList-zgc.txt +++ b/test/jdk/ProblemList-zgc.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,5 @@ # ############################################################################# -java/util/concurrent/locks/Lock/OOMEInAQS.java 8309218 generic-all - sun/tools/jhsdb/JShellHeapDumpTest.java 8276539 generic-all sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8276539 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index e2499c97c64..13cf0feb231 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/build/releaseFile/CheckReleaseFile.java b/test/jdk/build/releaseFile/CheckReleaseFile.java index 79e9b38394d..1160b616223 100644 --- a/test/jdk/build/releaseFile/CheckReleaseFile.java +++ b/test/jdk/build/releaseFile/CheckReleaseFile.java @@ -29,34 +29,35 @@ */ import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CheckReleaseFile { - public static final String SRC_HASH_REGEXP = ":((hg)|(git)):[a-z0-9]*\\+?"; + public static final String SRC_HASH_REGEXP = ":git:[a-z0-9]*\\+?"; - private final boolean isOpenJDK; - CheckReleaseFile(String dataFile, boolean isOpenJDK) { - this.isOpenJDK = isOpenJDK; - // Read data files - readFile(dataFile); + public static void main(String args[]) throws IOException { + String jdkPath = System.getProperty("test.jdk"); + String runtime = System.getProperty("java.runtime.name"); + + System.out.println("JDK Path : " + jdkPath); + System.out.println("Runtime Name : " + runtime); + + checkReleaseFile(Path.of(jdkPath)); } - private void readFile(String fileName) { - String fishForSOURCE = null; - String implementor = null; + private static void checkReleaseFile(Path javaHome) throws IOException { + String source = null; String runtimeVersion = null; - File file = new File(fileName); + Path releaseFile = javaHome.resolve("release"); // open the stream to read in for Entries - try (BufferedReader buffRead = - new BufferedReader(new FileReader(fileName))) { + try (BufferedReader buffRead = Files.newBufferedReader(releaseFile)) { // this is the string read String readIn; @@ -71,13 +72,7 @@ private void readFile(String fileName) { // grab SOURCE line if (readIn.startsWith("SOURCE=")) { - fishForSOURCE = readIn; - continue; - } - - // grab IMPLEMENTOR line - if (readIn.startsWith("IMPLEMENTOR=")) { - implementor = readIn; + source = readIn; continue; } @@ -87,22 +82,13 @@ private void readFile(String fileName) { continue; } } - } catch (FileNotFoundException fileExcept) { - throw new RuntimeException("File " + fileName + - " not found reading data!", fileExcept); - } catch (IOException ioExcept) { - throw new RuntimeException("Unexpected problem reading data!", - ioExcept); } // was SOURCE even found? - if (fishForSOURCE == null) { + if (source == null) { throw new RuntimeException("SOURCE line was not found!"); } - - // Check if implementor is Oracle - boolean isOracle = (implementor != null) && implementor.contains("Oracle Corporation"); - checkSource(fishForSOURCE, isOracle); + checkSource(source); if (runtimeVersion == null) { throw new RuntimeException("JAVA_RUNTIME_VERSION line was not found!"); @@ -114,13 +100,13 @@ private void readFile(String fileName) { } } - private void checkSource(String fishForSOURCE, boolean isOracle) { + private static void checkSource(String source) { - System.out.println("The source string found: " + fishForSOURCE); + System.out.println("The source string found: " + source); // Extract the value of SOURCE= Pattern valuePattern = Pattern.compile("SOURCE=\"(.*)\""); - Matcher valueMatcher = valuePattern.matcher(fishForSOURCE); + Matcher valueMatcher = valuePattern.matcher(source); if (!valueMatcher.matches()) { throw new RuntimeException("SOURCE string has bad format, should be SOURCE=\"\""); } @@ -137,36 +123,19 @@ private void checkSource(String fishForSOURCE, boolean isOracle) { // If it's an Oracle build, it can be either OpenJDK or OracleJDK. Other // builds may have any number of additional elements in any format. - if (isOracle) { - if (isOpenJDK) { - if (values.length != 1) { - throw new RuntimeException("The test failed, wrong number of elements in SOURCE list." + - " Should be 1 for Oracle built OpenJDK."); - } - } else { - if (values.length != 2) { - throw new RuntimeException("The test failed, wrong number of elements in SOURCE list." + - " Should be 2 for OracleJDK."); - } - // Second value MUST start with "open:" for OracleJDK - String openRegexp = "open" + SRC_HASH_REGEXP; - if (!values[1].matches(openRegexp)) { - throw new RuntimeException("The test failed, second element did not match regexp: " + openRegexp); - } + String runtime = System.getProperty("java.runtime.name"); + String vendor = System.getProperty("java.vendor"); + if (runtime.contains("OpenJDK") && vendor.contains("Oracle Corporation")) { + System.out.println("Oracle built OpenJDK, verifying SOURCE format"); + if (values.length != 1) { + throw new RuntimeException("The test failed, wrong number of elements in SOURCE list." + + " Should be 1 for Oracle built OpenJDK."); } + } else { + System.out.println("Not Oracle built OpenJDK, skipping further SOURCE verification"); } // Everything was fine System.out.println("The test passed!"); } - - public static void main(String args[]) { - String jdkPath = System.getProperty("test.jdk"); - String runtime = System.getProperty("java.runtime.name"); - - System.out.println("JDK Path : " + jdkPath); - System.out.println("Runtime Name : " + runtime); - - new CheckReleaseFile(jdkPath + "/release", runtime.contains("OpenJDK")); - } } diff --git a/test/jdk/com/sun/jdi/BadAgentPath.java b/test/jdk/com/sun/jdi/BadAgentPath.java index 68f28701cdc..3ef0adadc84 100644 --- a/test/jdk/com/sun/jdi/BadAgentPath.java +++ b/test/jdk/com/sun/jdi/BadAgentPath.java @@ -38,7 +38,7 @@ public class BadAgentPath { public static void main(String[] args) throws Throwable { - OutputAnalyzer output = ProcessTools.executeTestJvm("-agentpath:/badAgent/agent", "-version"); + OutputAnalyzer output = ProcessTools.executeTestJava("-agentpath:/badAgent/agent", "-version"); output.shouldContain("Could not find agent library /badAgent/agent"); } } diff --git a/test/jdk/com/sun/jdi/DoubleAgentTest.java b/test/jdk/com/sun/jdi/DoubleAgentTest.java index 99ec6091aaf..ea2a109ed9b 100644 --- a/test/jdk/com/sun/jdi/DoubleAgentTest.java +++ b/test/jdk/com/sun/jdi/DoubleAgentTest.java @@ -44,7 +44,7 @@ public static void main(String[] args) throws Throwable { String jdwpOption = "-agentlib:jdwp=transport=dt_socket" + ",server=y" + ",suspend=n" + ",address=*:0"; - OutputAnalyzer output = ProcessTools.executeTestJvm("-classpath", + OutputAnalyzer output = ProcessTools.executeTestJava("-classpath", TEST_CLASSES, jdwpOption, // Notice jdwpOption specified twice jdwpOption, diff --git a/test/jdk/com/sun/jdi/JdwpAllowTest.java b/test/jdk/com/sun/jdi/JdwpAllowTest.java index a5c756f8790..c23b0a2ff8c 100644 --- a/test/jdk/com/sun/jdi/JdwpAllowTest.java +++ b/test/jdk/com/sun/jdi/JdwpAllowTest.java @@ -57,7 +57,7 @@ public static int handshake(int port) throws IOException { res = s.getInputStream().read(buffer); } catch (SocketException ex) { - ex.printStackTrace(); + ex.printStackTrace(System.out); // pass } finally { if (s != null) { @@ -98,7 +98,7 @@ private static int detectPort(LingeredApp app) { public static void positiveTest(String testName, String allowOpt) throws InterruptedException, IOException { - System.err.println("\nStarting " + testName); + System.out.println("\nStarting " + testName); String[] cmd = prepareCmd(allowOpt); LingeredApp a = LingeredApp.startApp(cmd); @@ -111,12 +111,12 @@ public static void positiveTest(String testName, String allowOpt) if (res < 0) { throw new RuntimeException(testName + " FAILED"); } - System.err.println(testName + " PASSED"); + System.out.println(testName + " PASSED"); } public static void negativeTest(String testName, String allowOpt) throws InterruptedException, IOException { - System.err.println("\nStarting " + testName); + System.out.println("\nStarting " + testName); String[] cmd = prepareCmd(allowOpt); LingeredApp a = LingeredApp.startApp(cmd); @@ -127,24 +127,24 @@ public static void negativeTest(String testName, String allowOpt) a.stopApp(); } if (res > 0) { - System.err.println(testName + ": res=" + res); + System.out.println(testName + ": res=" + res); throw new RuntimeException(testName + " FAILED"); } - System.err.println(testName + ": returned a negative code as expected: " + res); - System.err.println(testName + " PASSED"); + System.out.println(testName + ": returned a negative code as expected: " + res); + System.out.println(testName + " PASSED"); } public static void badAllowOptionTest(String testName, String allowOpt) throws InterruptedException, IOException { - System.err.println("\nStarting " + testName); + System.out.println("\nStarting " + testName); String[] cmd = prepareCmd(allowOpt); LingeredApp a; try { a = LingeredApp.startApp(cmd); } catch (IOException ex) { - System.err.println(testName + ": caught expected IOException"); - System.err.println(testName + " PASSED"); + System.out.println(testName + ": caught expected IOException"); + System.out.println(testName + " PASSED"); return; } // LingeredApp.startApp is expected to fail, but if not, terminate the app @@ -154,7 +154,7 @@ public static void badAllowOptionTest(String testName, String allowOpt) /* * Generate allow address by changing random bit in the local address - * and calculate 2 masks (prefix length) - one is matches original local address + * and calculate 2 masks (prefix length) - one matches original local address * and another doesn't. */ private static class MaskTest { @@ -167,8 +167,16 @@ public MaskTest(InetAddress addr) throws Exception { localAddress = addr.getHostAddress(); byte[] bytes = addr.getAddress(); Random r = new Random(); - // prefix length must be >= 1, so bitToChange must be >= 2 - int bitToChange = r.nextInt(bytes.length * 8 - 3) + 2; + // Prefix length is 1..32 for IPv4, 1..128 for IPv6. + // bitToChange is zero-based and must be >0 (for 0 "good" prefix length would be 0). + // Corner cases (for 127.0.0.1): + // bitToChange == 1 => allow address = 0.0.0.0 + // - "good" allow mask is "0.0.0.0/1"; + // - "bad" allow mask is "0.0.0.0/2"; + // bitToChange == 31 => allow address = 127.0.0.0 + // - "good" allow mask is "127.0.0.0/31"; + // - "bad" allow mask is "127.0.0.0/32". + int bitToChange = r.nextInt(bytes.length * 8 - 2) + 1; setBit(bytes, bitToChange, !getBit(bytes, bitToChange)); // clear rest of the bits for mask address for (int i = bitToChange + 1; i < bytes.length * 8; i++) { @@ -176,8 +184,8 @@ public MaskTest(InetAddress addr) throws Exception { } allowAddress = InetAddress.getByAddress(bytes).getHostAddress(); - prefixLengthBad = bitToChange; - prefixLengthGood = bitToChange - 1; + prefixLengthGood = bitToChange; + prefixLengthBad = bitToChange + 1; } private static boolean getBit(byte[] bytes, int pos) { @@ -203,7 +211,7 @@ private static void init() throws Exception { throw new RuntimeException("No addresses is returned for 'localhost'"); } localAddr = addrs[0].getHostAddress(); - System.err.println("localhost address: " + localAddr); + System.out.println("localhost address: " + localAddr); for (int i = 0; i < addrs.length; i++) { maskTests.add(new MaskTest(addrs[i])); @@ -243,11 +251,11 @@ public static void main(String[] args) throws Exception { localAddr = test.localAddress; positiveTest("PositiveMaskTest(" + test.localAddress + ")", test.allowAddress + "/" + test.prefixLengthGood); - positiveTest("NegativeMaskTest(" + test.localAddress + ")", + negativeTest("NegativeMaskTest(" + test.localAddress + ")", test.allowAddress + "/" + test.prefixLengthBad); } - System.err.println("\nTest PASSED"); + System.out.println("\nTest PASSED"); } } diff --git a/test/jdk/com/sun/jdi/OnJcmdTest.java b/test/jdk/com/sun/jdi/OnJcmdTest.java index 6cc417497c6..c7f93e6fb31 100644 --- a/test/jdk/com/sun/jdi/OnJcmdTest.java +++ b/test/jdk/com/sun/jdi/OnJcmdTest.java @@ -51,12 +51,12 @@ private static String getListenerAddress() throws Exception { public static void main(String[] args) throws Throwable { // First check if we get the expected errors. - OutputAnalyzer output = ProcessTools.executeTestJvm( + OutputAnalyzer output = ProcessTools.executeTestJava( "-agentlib:jdwp=transport=dt_socket,address=any,onjcmd=y"); output.shouldContain("Can only use onjcmd with server=y"); output.shouldHaveExitValue(1); - output = ProcessTools.executeTestJvm( + output = ProcessTools.executeTestJava( "-agentlib:jdwp=transport=dt_socket,address=any,onjcmd=y,onthrow=a,launch=a"); output.shouldContain("Cannot combine onjcmd and launch suboptions"); output.shouldHaveExitValue(1); diff --git a/test/jdk/com/sun/jdi/SuspendNoFlagTest.java b/test/jdk/com/sun/jdi/SuspendNoFlagTest.java index 98b32063c74..31e717a63d0 100644 --- a/test/jdk/com/sun/jdi/SuspendNoFlagTest.java +++ b/test/jdk/com/sun/jdi/SuspendNoFlagTest.java @@ -38,7 +38,7 @@ public class SuspendNoFlagTest { "test.classes", "."); public static void main(String[] args) throws Throwable { - OutputAnalyzer output = ProcessTools.executeTestJvm("-classpath", + OutputAnalyzer output = ProcessTools.executeTestJava("-classpath", TEST_CLASSES, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n", "HelloWorld"); diff --git a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java index c7fded7399e..7db226617ff 100644 --- a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java +++ b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ * @summary Basic test of ThreadMXBean.getThreadCpuTime(long[]) and * getThreadUserTime(long[]). * @author Paul Hohensee + * @run main/othervm ThreadCpuTimeArray */ import java.lang.management.*; diff --git a/test/jdk/com/sun/tools/attach/BasicTests.java b/test/jdk/com/sun/tools/attach/BasicTests.java index ff1849984d4..833d7022ce8 100644 --- a/test/jdk/com/sun/tools/attach/BasicTests.java +++ b/test/jdk/com/sun/tools/attach/BasicTests.java @@ -101,7 +101,7 @@ private static void runTests(long pid) throws Throwable { testClassDir + "Agent.jar", testClassDir + "BadAgent.jar", testClassDir + "RedefineAgent.jar" }; - OutputAnalyzer output = ProcessTools.executeTestJvm(args); + OutputAnalyzer output = ProcessTools.executeTestJava(args); output.shouldHaveExitValue(0); } diff --git a/test/jdk/com/sun/tools/attach/PermissionTest.java b/test/jdk/com/sun/tools/attach/PermissionTest.java index 3a4128a9472..bf9473b0c8c 100644 --- a/test/jdk/com/sun/tools/attach/PermissionTest.java +++ b/test/jdk/com/sun/tools/attach/PermissionTest.java @@ -86,7 +86,7 @@ private static void runTests(long pid) throws Throwable { "PermissionTest$TestMain", Long.toString(pid), "true" }; - OutputAnalyzer output = ProcessTools.executeTestJvm(args); + OutputAnalyzer output = ProcessTools.executeTestJava(args); output.shouldHaveExitValue(0); // Use a policy that will allow attach. @@ -98,7 +98,7 @@ private static void runTests(long pid) throws Throwable { "PermissionTest$TestMain", Long.toString(pid), "false" }; - output = ProcessTools.executeTestJvm(args); + output = ProcessTools.executeTestJava(args); output.shouldHaveExitValue(0); } diff --git a/test/jdk/com/sun/tools/attach/ProviderTest.java b/test/jdk/com/sun/tools/attach/ProviderTest.java index 5359d4241db..e006bfd6b6d 100644 --- a/test/jdk/com/sun/tools/attach/ProviderTest.java +++ b/test/jdk/com/sun/tools/attach/ProviderTest.java @@ -79,7 +79,7 @@ private static void runTests() throws Throwable { "-classpath", classpath, "ProviderTest$TestMain" }; - OutputAnalyzer output = ProcessTools.executeTestJvm(args); + OutputAnalyzer output = ProcessTools.executeTestJava(args); output.shouldHaveExitValue(0); } diff --git a/test/jdk/com/sun/tools/attach/TempDirTest.java b/test/jdk/com/sun/tools/attach/TempDirTest.java index 2d932ffcf0e..b9ce4acb141 100644 --- a/test/jdk/com/sun/tools/attach/TempDirTest.java +++ b/test/jdk/com/sun/tools/attach/TempDirTest.java @@ -140,7 +140,7 @@ private static void launchTests(long pid, Path clientTmpDir) throws Throwable { classpath, "TempDirTest$TestMain", Long.toString(pid) }); - OutputAnalyzer output = ProcessTools.executeTestJvm(args); + OutputAnalyzer output = ProcessTools.executeTestJava(args); output.shouldHaveExitValue(0); } diff --git a/test/jdk/java/foreign/TestAddressDereference.java b/test/jdk/java/foreign/TestAddressDereference.java index 3ebec596263..54477bafe13 100644 --- a/test/jdk/java/foreign/TestAddressDereference.java +++ b/test/jdk/java/foreign/TestAddressDereference.java @@ -128,8 +128,8 @@ public void testNativeUpcallArgNeg(long alignment, ValueLayout layout) throws Th if (!badAlign) return; runInNewProcess(UpcallTestRunner.class, true, new String[] {Long.toString(alignment), layout.toString() }) - .assertFailed() - .assertStdErrContains("alignment constraint for address"); + .shouldNotHaveExitValue(0) + .stderrShouldContain("alignment constraint for address"); } public static class UpcallTestRunner { diff --git a/test/jdk/java/foreign/TestArrayCopy.java b/test/jdk/java/foreign/TestArrayCopy.java index 0a04f00e4f5..9a1c48a394e 100644 --- a/test/jdk/java/foreign/TestArrayCopy.java +++ b/test/jdk/java/foreign/TestArrayCopy.java @@ -26,12 +26,9 @@ * @run testng TestArrayCopy */ -import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; import java.util.ArrayList; @@ -240,7 +237,7 @@ public void testCopyReadOnlyDest(CopyMode mode, CopyHelper try { helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder()); fail(); - } catch (UnsupportedOperationException ex) { + } catch (IllegalArgumentException ex) { //ok } } diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index f4048aaa68a..2aa398468cc 100644 --- a/test/jdk/java/foreign/TestLayouts.java +++ b/test/jdk/java/foreign/TestLayouts.java @@ -371,13 +371,13 @@ public void testVarHandleCaching() { } @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*Negative offset.*") + expectedExceptionsMessageRegExp=".*offset is negative.*") public void testScaleNegativeOffset() { JAVA_INT.scale(-1, 0); } @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*Negative index.*") + expectedExceptionsMessageRegExp=".*index is negative.*") public void testScaleNegativeIndex() { JAVA_INT.scale(0, -1); } diff --git a/test/jdk/java/foreign/TestMemoryAccess.java b/test/jdk/java/foreign/TestMemoryAccess.java index 19f480aa4b2..ded9be1c085 100644 --- a/test/jdk/java/foreign/TestMemoryAccess.java +++ b/test/jdk/java/foreign/TestMemoryAccess.java @@ -87,7 +87,7 @@ private void testAccessInternal(Function viewFacto if (isRO) { throw new AssertionError(); //not ok, memory should be immutable } - } catch (UnsupportedOperationException ex) { + } catch (IllegalArgumentException ex) { if (!isRO) { throw new AssertionError(); //we should not have failed! } @@ -121,7 +121,7 @@ private void testArrayAccessInternal(Function view if (isRO) { throw new AssertionError(); //not ok, memory should be immutable } - } catch (UnsupportedOperationException ex) { + } catch (IllegalArgumentException ex) { if (!isRO) { throw new AssertionError(); //we should not have failed! } @@ -185,7 +185,7 @@ private void testMatrixAccessInternal(Function vie if (isRO) { throw new AssertionError(); //not ok, memory should be immutable } - } catch (UnsupportedOperationException ex) { + } catch (IllegalArgumentException ex) { if (!isRO) { throw new AssertionError(); //we should not have failed! } diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index a1c774b72dd..b749c96ac54 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -27,7 +27,6 @@ * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_SEGMENT_FORCE_EXACT=true --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance */ -import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.Arena; import java.lang.foreign.ValueLayout; @@ -165,6 +164,13 @@ public void badAccessOverflowInIndexedAccess(String t } } + @Test(dataProvider = "segmentAccessors") + public void negativeOffset(String testName, Accessor accessor) { + MemorySegment segment = MemorySegment.ofArray(new byte[100]); + assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, -ValueLayout.JAVA_LONG.byteSize(), accessor.value)); + } + static final ByteOrder NE = ByteOrder.nativeOrder(); @DataProvider(name = "segmentAccessors") diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java index 70223c00c00..d680d234145 100644 --- a/test/jdk/java/foreign/TestScopedOperations.java +++ b/test/jdk/java/foreign/TestScopedOperations.java @@ -27,6 +27,7 @@ */ import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -135,6 +136,8 @@ public void testOpOutsideConfinement(String name, ScopedOperation scopedO ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_FLOAT, new float[]{0}), "Arena::allocateFrom/float"); ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_LONG, new long[]{0}), "Arena::allocateFrom/long"); ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_DOUBLE, new double[]{0}), "Arena::allocateFrom/double"); + var source = MemorySegment.ofArray(new byte[]{}); + ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg"); }; @DataProvider(name = "scopedOperations") diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java index 48e09f647c9..87418f39d90 100644 --- a/test/jdk/java/foreign/TestSegmentAllocators.java +++ b/test/jdk/java/foreign/TestSegmentAllocators.java @@ -44,6 +44,8 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.Function; @@ -100,6 +102,16 @@ public void testAllocation(Z value, AllocationFactory static final int SIZE_256M = 1024 * 1024 * 256; + @Test(expectedExceptions = IllegalArgumentException.class) + public void testReadOnlySlicingAllocator() { + SegmentAllocator.slicingAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testReadOnlyPrefixAllocator() { + SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); + } + @Test public void testBigAllocationInUnboundedSession() { try (Arena arena = Arena.ofConfined()) { @@ -160,6 +172,100 @@ public void testBadArenaNullReturn() { } } + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + public void testArenaAllocateFromHeapSegment() { + try (Arena arena = Arena.ofConfined()) { + var heapSegment = MemorySegment.ofArray(new int[]{1}); + arena.allocateFrom(ValueLayout.ADDRESS, heapSegment); + } + } + + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + public void testAllocatorAllocateFromHeapSegment() { + try (Arena arena = Arena.ofConfined()) { + SegmentAllocator allocator = SegmentAllocator.prefixAllocator(arena.allocate(16)); + var heapSegment = MemorySegment.ofArray(new int[]{1}); + allocator.allocateFrom(ValueLayout.ADDRESS, heapSegment); + } + } + + // Invariant checking tests for the SegmentAllocator method: + // MemorySegment allocateFrom(ValueLayout elementLayout, + // MemorySegment source, + // ValueLayout sourceElementLayout, + // long sourceOffset, + // long elementCount) { + @Test + public void testAllocatorAllocateFromArguments() { + try (Arena arena = Arena.ofConfined()) { + var sourceElements = 2; + var source = arena.allocate(ValueLayout.JAVA_LONG, sourceElements); + var elementLayout = ValueLayout.JAVA_INT; + var sourceElementLayout = ValueLayout.JAVA_INT; + + // IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, ValueLayout.JAVA_BYTE, 0, 1) + ); + + // IllegalArgumentException if source segment/offset + // are incompatible with the alignment constraint + // in the source element layout + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source.asSlice(1), sourceElementLayout, 0, 1) + ); + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 1, 1) + ); + + // IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout.withByteAlignment(elementLayout.byteAlignment() * 2), source, sourceElementLayout, 1, 1) + ); + + // IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated + // with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} + // This is tested in TestScopedOperations + + // WrongThreadException if this method is called from a thread {@code T}, + // such that {@code source.isAccessibleBy(T) == false} + CompletableFuture future = CompletableFuture.supplyAsync(Arena::ofConfined); + try { + Arena otherThreadArena = future.get(); + assertThrows(WrongThreadException.class, () -> + otherThreadArena.allocateFrom(elementLayout, source, sourceElementLayout, 0, 1) + ); + } catch (ExecutionException | InterruptedException e) { + fail("Unable to create arena", e); + } + + // IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, Long.MAX_VALUE) + ); + + // IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} + assertThrows(IndexOutOfBoundsException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, source.byteSize() - (1 * sourceElementLayout.byteAlignment()) + elementLayout.byteSize(), 1) + ); + + // IndexOutOfBoundsException if {@code sourceOffset < 0} + assertThrows(IndexOutOfBoundsException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, -elementLayout.byteSize(), 1) + ); + + // IllegalArgumentException if {@code elementCount < 0} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, -1) + ); + + + } + } + + @Test public void testArrayAllocateDelegation() { AtomicInteger calls = new AtomicInteger(); diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 85f843eddd7..88636bf5420 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -76,7 +76,7 @@ public void testByteCopy(SegmentKind kind1, SegmentKind kind2) { } } - @Test(expectedExceptions = UnsupportedOperationException.class, dataProvider = "segmentKinds") + @Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "segmentKinds") public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); @@ -84,6 +84,15 @@ public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { MemorySegment.copy(s1, Type.BYTE.layout, 0, s2.asReadOnly(), Type.BYTE.layout, 0, 0); } + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*Attempt to write a read-only segment.*") + public void badCopy6Arg() { + try (Arena scope = Arena.ofConfined()) { + MemorySegment dest = scope.allocate(ValueLayout.JAVA_INT).asReadOnly(); + MemorySegment.copy(new int[1],0, dest, ValueLayout.JAVA_INT, 0 ,1); // should throw + } + } + @Test(expectedExceptions = IndexOutOfBoundsException.class, dataProvider = "types") public void testBadOverflow(Type type) { if (type.layout.byteSize() > 1) { @@ -136,6 +145,66 @@ public void testHyperAlignedDst() { MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4); } + @Test + public void testCopy5ArgWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, -1, dst, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, 0, -1) + ); + } + + @Test + public void testCopy7ArgWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, -1, dst, JAVA_BYTE, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, 0, -1) + ); + } + + @Test + public void testCopyFromArrayWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + byte[] dst = new byte[] {1, 2, 3, 4}; + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, -1, dst, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, 0, -1) + ); + } + + @Test + public void testCopyToArrayWithNegativeValues() { + byte[] src = new byte[] {1, 2, 3, 4}; + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, -1, dst, JAVA_BYTE, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, JAVA_BYTE, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, JAVA_BYTE, 0, -1) + ); + } + enum Type { // Byte BYTE(byte.class, JAVA_BYTE, i -> (byte)i), diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 940d96e844d..44ecd12ba5e 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -43,6 +43,7 @@ import java.util.function.Supplier; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.*; public class TestSegments { @@ -55,14 +56,13 @@ public void testBadAllocateAlign(long size, long align) { @Test public void testZeroLengthNativeSegment() { try (Arena arena = Arena.ofConfined()) { - Arena session = arena; - var segment = session.allocate(0, 1); + var segment = arena.allocate(0, 1); assertEquals(segment.byteSize(), 0); MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT); - segment = session.allocate(seq); + segment = arena.allocate(seq); assertEquals(segment.byteSize(), 0); assertEquals(segment.address() % seq.byteAlignment(), 0); - segment = session.allocate(0, 4); + segment = arena.allocate(0, 4); assertEquals(segment.byteSize(), 0); assertEquals(segment.address() % 4, 0); MemorySegment rawAddress = MemorySegment.ofAddress(segment.address()); @@ -133,8 +133,7 @@ public void testDerivedScopes(Supplier segmentSupplier) { @Test public void testEqualsOffHeap() { try (Arena arena = Arena.ofConfined()) { - Arena scope1 = arena; - MemorySegment segment = scope1.allocate(100, 1); + MemorySegment segment = arena.allocate(100, 1); assertEquals(segment, segment.asReadOnly()); assertEquals(segment, segment.asSlice(0, 100)); assertNotEquals(segment, segment.asSlice(10, 90)); @@ -325,12 +324,18 @@ public void testScopeGlobalArena() { assertEquals(segment.scope(), arena.scope()); } - @Test(dataProvider = "segmentFactories", expectedExceptions = UnsupportedOperationException.class) + @Test(dataProvider = "segmentFactories", expectedExceptions = IllegalArgumentException.class) public void testFillIllegalAccessMode(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); segment.asReadOnly().fill((byte) 0xFF); } + @Test(dataProvider = "segmentFactories", expectedExceptions = IllegalArgumentException.class) + public void testFromStringIllegalAccessMode(Supplier segmentSupplier) { + MemorySegment segment = segmentSupplier.get(); + segment.asReadOnly().setString(0, "a"); + } + @Test(dataProvider = "segmentFactories") public void testFillThread(Supplier segmentSupplier) throws Exception { MemorySegment segment = segmentSupplier.get(); diff --git a/test/jdk/java/foreign/TestStubAllocFailure.java b/test/jdk/java/foreign/TestStubAllocFailure.java index d3a1ef6e3de..b20b3e88ea2 100644 --- a/test/jdk/java/foreign/TestStubAllocFailure.java +++ b/test/jdk/java/foreign/TestStubAllocFailure.java @@ -31,12 +31,15 @@ */ import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.io.IOException; import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; public class TestStubAllocFailure extends UpcallTestHelper { @@ -44,18 +47,23 @@ public class TestStubAllocFailure extends UpcallTestHelper { @Test public void testUpcallAllocFailure() throws IOException, InterruptedException { runInNewProcess(UpcallRunner.class, true, List.of("-XX:ReservedCodeCacheSize=3M"), List.of()) - .assertSuccess(); + .shouldNotHaveExitValue(0) + .shouldNotHaveFatalError(); + } + + @Test + public void testUDowncallAllocFailure() throws IOException, InterruptedException { + runInNewProcess(DowncallRunner.class, true, List.of("-XX:ReservedCodeCacheSize=3M"), List.of()) + .shouldNotHaveExitValue(0) + .shouldNotHaveFatalError(); } public static class UpcallRunner extends NativeTestHelper { public static void main(String[] args) throws Throwable { - try (Arena arena = Arena.ofConfined()) { - while (true) { - // allocate stubs until we crash - upcallStub(UpcallRunner.class, "target", FunctionDescriptor.ofVoid(), arena); - } - } catch (OutOfMemoryError e) { - assertTrue(e.getMessage().contains("Failed to allocate upcall stub")); + FunctionDescriptor descriptor = FunctionDescriptor.ofVoid(); + MethodHandle target = MethodHandles.lookup().findStatic(UpcallRunner.class, "target", descriptor.toMethodType()); + while (true) { + LINKER.upcallStub(target, descriptor, Arena.ofAuto()); } } @@ -63,4 +71,25 @@ public static void target() { fail("Should not get here"); } } + + public static class DowncallRunner extends NativeTestHelper { + + private static final int MAX_ARITY = 5; + + private static void mapper(FunctionDescriptor fd, Consumer sink) { + for (MemoryLayout l : List.of(C_INT, C_LONG_LONG, C_DOUBLE, C_FLOAT, C_SHORT)) { + sink.accept(fd.appendArgumentLayouts(l)); + } + } + + public static void main(String[] args) throws Throwable { + Linker linker = Linker.nativeLinker(); + Stream stream = Stream.of(FunctionDescriptor.ofVoid()); + for (int i = 0; i < MAX_ARITY; i++) { + stream = stream.mapMulti(DowncallRunner::mapper); + } + + stream.forEach(linker::downcallHandle); + } + } } diff --git a/test/jdk/java/foreign/TestUpcallException.java b/test/jdk/java/foreign/TestUpcallException.java index f7dca7bc19c..beaa33f5e61 100644 --- a/test/jdk/java/foreign/TestUpcallException.java +++ b/test/jdk/java/foreign/TestUpcallException.java @@ -48,8 +48,8 @@ public class TestUpcallException extends UpcallTestHelper { @Test(dataProvider = "exceptionCases") public void testException(Class target, boolean useSpec) throws InterruptedException, IOException { runInNewProcess(target, useSpec) - .assertFailed() - .assertStdErrContains("Testing upcall exceptions"); + .shouldNotHaveExitValue(0) + .stderrShouldContain("Testing upcall exceptions"); } @DataProvider diff --git a/test/jdk/java/foreign/UpcallTestHelper.java b/test/jdk/java/foreign/UpcallTestHelper.java index e24c35e498c..8adf5580f51 100644 --- a/test/jdk/java/foreign/UpcallTestHelper.java +++ b/test/jdk/java/foreign/UpcallTestHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,54 +21,25 @@ * questions. */ +import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; public class UpcallTestHelper extends NativeTestHelper { - public record Output(int result, List stdout, List stderr) { - private static void assertContains(List lines, String shouldInclude, String name) { - assertTrue(lines.stream().anyMatch(line -> line.contains(shouldInclude)), - "Did not find '" + shouldInclude + "' in " + name); - } - - public Output assertFailed() { - assertNotEquals(result, 0); - return this; - } - - public Output assertSuccess() { - assertEquals(result, 0); - return this; - } - - public Output assertStdErrContains(String shouldInclude) { - assertContains(stderr, shouldInclude, "stderr"); - return this; - } - public Output assertStdOutContains(String shouldInclude) { - assertContains(stdout, shouldInclude, "stdout"); - return this; - } - } - - public Output runInNewProcess(Class target, boolean useSpec, String... programArgs) throws IOException, InterruptedException { + public OutputAnalyzer runInNewProcess(Class target, boolean useSpec, String... programArgs) throws IOException, InterruptedException { return runInNewProcess(target, useSpec, List.of(), List.of(programArgs)); } - public Output runInNewProcess(Class target, boolean useSpec, List vmArgs, List programArgs) throws IOException, InterruptedException { + public OutputAnalyzer runInNewProcess(Class target, boolean useSpec, List vmArgs, List programArgs) throws IOException, InterruptedException { assert !target.isArray(); List command = new ArrayList<>(List.of( @@ -80,23 +51,18 @@ public Output runInNewProcess(Class target, boolean useSpec, List vmA command.add(target.getName()); command.addAll(programArgs); - Process process = ProcessTools.createTestJavaProcessBuilder(command).start(); - - long timeOut = (long) (Utils.TIMEOUT_FACTOR * 1L); - boolean completed = process.waitFor(timeOut, TimeUnit.MINUTES); - assertTrue(completed, "Time out while waiting for process"); - - List outLines = linesFromStream(process.getInputStream()); - outLines.forEach(System.out::println); - List errLines = linesFromStream(process.getErrorStream()); - errLines.forEach(System.err::println); - - return new Output(process.exitValue(), outLines, errLines); - } - - private static List linesFromStream(InputStream stream) throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { - return reader.lines().toList(); + try { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(command); + // note that it's important to use ProcessTools.startProcess here since this makes sure output streams of the + // fork don't fill up, which could make the process stall while writing to stdout/stderr + Process process = ProcessTools.startProcess(target.getName(), pb, null, null, 1L, TimeUnit.MINUTES); + OutputAnalyzer output = new OutputAnalyzer(process); + output.outputTo(System.out); + output.errorTo(System.err); + return output; + } catch (TimeoutException e) { + fail("Timeout while waiting for forked process"); + return null; } } } diff --git a/test/jdk/java/foreign/critical/TestCriticalUpcall.java b/test/jdk/java/foreign/critical/TestCriticalUpcall.java index c2f2d5572c1..862c008b080 100644 --- a/test/jdk/java/foreign/critical/TestCriticalUpcall.java +++ b/test/jdk/java/foreign/critical/TestCriticalUpcall.java @@ -43,7 +43,9 @@ public class TestCriticalUpcall extends UpcallTestHelper { @Test public void testUpcallFailure() throws IOException, InterruptedException { // test to see if we catch a trivial downcall doing an upcall - runInNewProcess(Runner.class, true).assertFailed().assertStdOutContains("wrong thread state for upcall"); + runInNewProcess(Runner.class, true) + .shouldNotHaveExitValue(0) + .stdoutShouldContain("wrong thread state for upcall"); } public static class Runner extends NativeTestHelper { diff --git a/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java b/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java index 5f97dbf288d..fadcdf1ba24 100644 --- a/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java +++ b/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java @@ -53,7 +53,9 @@ public void testNoHeapArgs() throws Throwable { @Test(dataProvider = "specs") public void testNoHeapReturns(boolean spec) throws IOException, InterruptedException { - runInNewProcess(Runner.class, spec).assertFailed().assertStdErrContains("Heap segment not allowed"); + runInNewProcess(Runner.class, spec) + .shouldNotHaveExitValue(0) + .stderrShouldContain("Heap segment not allowed"); } public static class Runner { diff --git a/test/jdk/java/io/BufferedInputStream/TransferToTrusted.java b/test/jdk/java/io/BufferedInputStream/TransferToTrusted.java new file mode 100644 index 00000000000..c0bd7b53af8 --- /dev/null +++ b/test/jdk/java/io/BufferedInputStream/TransferToTrusted.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.*; +import java.util.Arrays; +import java.util.Objects; +import java.util.Random; + +/* + * @test + * @bug 8320971 + * @summary Verify BufferedInputStream.buf is used directly by + * BufferedInputStream.implTransferTo() only when its OutputStream + * parameter is trusted + * @key randomness + * @run main/othervm --add-opens=java.base/java.io=ALL-UNNAMED TransferToTrusted + */ +public class TransferToTrusted { + + private static final Random RND = new Random(System.nanoTime()); + + private static final class UntrustedOutputStream extends OutputStream { + + UntrustedOutputStream() { + super(); + } + + @Override + public void write(byte[] b, int off, int len) { + Objects.checkFromIndexSize(off, len, b.length); + byte[] tmp = new byte[len]; + RND.nextBytes(tmp); + System.arraycopy(tmp, 0, b, off, len); + } + + @Override + public void write(int b) throws IOException { + write(new byte[]{(byte) b}); + } + } + + public static void main(String[] args) throws Exception { + final int length = 128; + byte[] buf = new byte[length]; + RND.nextBytes(buf); + + var outputStreams = new OutputStream[]{ + new ByteArrayOutputStream(), + new FileOutputStream(File.createTempFile(TransferToTrusted.class.getName(), null)), + new PipedOutputStream(new PipedInputStream(length)), + new UntrustedOutputStream() + }; + + for (var out : outputStreams) { + System.err.println("out: " + out.getClass().getName()); + + var bis = new BufferedInputStream(new ByteArrayInputStream(buf.clone())); + try (out; bis) { + bis.read();//need this to fill the BIS.buf in + bis.transferTo(out); + var internalBuffer = bis.getClass().getDeclaredField("buf"); + internalBuffer.setAccessible(true); + if (!Arrays.equals(buf, Arrays.copyOf((byte[]) internalBuffer.get(bis), length))) { + throw new RuntimeException("Internal buffer was modified"); + } + } + } + } +} diff --git a/test/jdk/java/io/File/GetCanonicalPath.java b/test/jdk/java/io/File/GetCanonicalPath.java index 0abf25244d2..e54227e44b4 100644 --- a/test/jdk/java/io/File/GetCanonicalPath.java +++ b/test/jdk/java/io/File/GetCanonicalPath.java @@ -23,7 +23,6 @@ /* @test * @bug 4899022 - * @requires (os.family == "windows") * @summary Look for erroneous representation of drive letter * @run junit GetCanonicalPath */ @@ -35,6 +34,8 @@ import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -43,7 +44,7 @@ import static org.junit.jupiter.api.Assertions.*; public class GetCanonicalPath { - private static Stream pathProvider() { + private static Stream pathProviderWindows() { List list = new ArrayList(); File dir = new File(System.getProperty("user.dir", ".")); @@ -80,21 +81,43 @@ private static Stream pathProvider() { return list.stream(); } + private static Stream pathProviderUnix() { + return Stream.of( + Arguments.of("/../../../../../a/b/c", "/a/b/c"), + Arguments.of("/../../../../../a/../b/c", "/b/c"), + Arguments.of("/../../../../../a/../../b/c", "/b/c"), + Arguments.of("/../../../../../a/../../../b/c", "/b/c"), + Arguments.of("/../../../../../a/../../../../b/c", "/b/c") + ); + } + + @ParameterizedTest + @EnabledOnOs({OS.AIX, OS.LINUX, OS.MAC}) + @MethodSource("pathProviderUnix") + void goodPathsUnix(String pathname, String expected) throws IOException { + File file = new File(pathname); + String canonicalPath = file.getCanonicalPath(); + assertEquals(expected, canonicalPath); + } + @ParameterizedTest + @EnabledOnOs(OS.WINDOWS) @ValueSource(strings = {"\\\\?", "\\\\?\\UNC", "\\\\?\\UNC\\"}) - void badPaths(String pathname) { + void badPathsWindows(String pathname) { assertThrows(IOException.class, () -> new File(pathname).getCanonicalPath()); } @ParameterizedTest - @MethodSource("pathProvider") - void goodPaths(String pathname, String expected) throws IOException { + @EnabledOnOs(OS.WINDOWS) + @MethodSource("pathProviderWindows") + void goodPathsWindows(String pathname, String expected) throws IOException { File file = new File(pathname); String canonicalPath = file.getCanonicalPath(); assertEquals(expected, canonicalPath); } @Test + @EnabledOnOs(OS.WINDOWS) void driveLetter() throws IOException { String path = new File("c:/").getCanonicalPath(); assertFalse(path.length() > 3, "Drive letter incorrectly represented"); diff --git a/test/jdk/java/io/File/TempDirDoesNotExist.java b/test/jdk/java/io/File/TempDirDoesNotExist.java index bb59f6f9aeb..f1c69f58654 100644 --- a/test/jdk/java/io/File/TempDirDoesNotExist.java +++ b/test/jdk/java/io/File/TempDirDoesNotExist.java @@ -124,21 +124,21 @@ public static Stream counterSource() { @ParameterizedTest @MethodSource("tempDirSource") public void existingMessage(List options) throws Exception { - ProcessTools.executeTestJvm(options).shouldContain(WARNING) + ProcessTools.executeTestJava(options).shouldContain(WARNING) .shouldHaveExitValue(0); } @ParameterizedTest @MethodSource("noTempDirSource") public void nonexistentMessage(List options) throws Exception { - ProcessTools.executeTestJvm(options).shouldNotContain(WARNING) + ProcessTools.executeTestJava(options).shouldNotContain(WARNING) .shouldHaveExitValue(0); } @ParameterizedTest @MethodSource("counterSource") public void messageCounter(List options) throws Exception { - OutputAnalyzer originalOutput = ProcessTools.executeTestJvm(options); + OutputAnalyzer originalOutput = ProcessTools.executeTestJava(options); long count = originalOutput.asLines().stream().filter( line -> line.equalsIgnoreCase(WARNING)).count(); assertEquals(1, count, diff --git a/test/jdk/java/io/FilePermission/MergeName.java b/test/jdk/java/io/FilePermission/MergeName.java index c2eff765f2d..715b9851209 100644 --- a/test/jdk/java/io/FilePermission/MergeName.java +++ b/test/jdk/java/io/FilePermission/MergeName.java @@ -81,7 +81,7 @@ private static void test(String file, String... actions) throws Exception { } content.add("};"); Files.write(Paths.get(file), content); - ProcessTools.executeTestJvm("-Djava.security.manager", + ProcessTools.executeTestJava("-Djava.security.manager", "-Djava.security.policy=" + file, "MergeName", "x", diff --git a/test/jdk/java/io/FilePermission/ReadFileOnPath.java b/test/jdk/java/io/FilePermission/ReadFileOnPath.java index acc66dac6ab..06e2c6c435a 100644 --- a/test/jdk/java/io/FilePermission/ReadFileOnPath.java +++ b/test/jdk/java/io/FilePermission/ReadFileOnPath.java @@ -87,7 +87,7 @@ static void test(String... args) throws Exception { cmds.addAll(List.of( "x", "modules/m", "modules/m/base", "modules/m/p/child", "-", "child", "/base", "../base")); - ProcessTools.executeTestJvm(cmds.toArray(new String[cmds.size()])) + ProcessTools.executeTestJava(cmds.toArray(new String[cmds.size()])) .shouldHaveExitValue(0); } } diff --git a/test/jdk/java/io/SequenceInputStream/TransferTo.java b/test/jdk/java/io/SequenceInputStream/TransferTo.java index a39d2c1e013..4c8ff71a4f3 100644 --- a/test/jdk/java/io/SequenceInputStream/TransferTo.java +++ b/test/jdk/java/io/SequenceInputStream/TransferTo.java @@ -24,6 +24,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.io.IOException; import java.io.OutputStream; import java.io.SequenceInputStream; import java.util.Arrays; @@ -39,6 +40,7 @@ import static java.lang.String.format; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; @@ -126,6 +128,49 @@ public void testStreamContents() throws Exception { outputStreamProvider, createRandomBytes(4096, 0), 0, 4096); } + /* + * Special case: Assert subsequent input stream is read when preceding stream already was MAX_VALUE long. + * Note: Not testing actual content as it requires multiple GBs of memory and long time. + */ + @Test + public void testHugeStream() throws Exception { + InputStream is1 = repeat(0, Long.MAX_VALUE); + InputStream is2 = repeat(0, 1); + assertNotEquals(is1.available(), 0); + assertNotEquals(is2.available(), 0); + SequenceInputStream sis = new SequenceInputStream(is1, is2); + OutputStream nos = OutputStream.nullOutputStream(); + sis.transferTo(nos); + assertEquals(is1.available(), 0); + assertEquals(is2.available(), 0); + } + + /* + * Produces an input stream that returns b count times. + * Builds a dysfunctional mock that solely implements + * available() and transferTo() particually, + * but fails with any other operation. + */ + private static InputStream repeat(int b, long count) { + return new InputStream() { + private long pos; + @Override + public int available() throws IOException { + return (int) Math.min(count - pos, Integer.MAX_VALUE); + } + @Override + public int read() throws IOException { + throw new UnsupportedOperationException(); + } + @Override + public long transferTo(OutputStream os) throws IOException { + // skipping actual writing to os to spare time + pos += count; + return count; + } + }; + } + /* * Asserts that the transferred content is correct, i.e., compares the bytes * actually transferred to those expected. The position of the input and diff --git a/test/jdk/java/lang/Class/GenericStringTest.java b/test/jdk/java/lang/Class/GenericStringTest.java index eb621d73ab7..73a3ffed5ad 100644 --- a/test/jdk/java/lang/Class/GenericStringTest.java +++ b/test/jdk/java/lang/Class/GenericStringTest.java @@ -23,9 +23,8 @@ /* * @test - * @bug 6298888 6992705 8161500 6304578 + * @bug 6298888 6992705 8161500 6304578 8322878 * @summary Check Class.toGenericString() - * @author Joseph D. Darcy * @enablePreview * @compile GenericStringTest.java * @run main/othervm GenericStringTest @@ -40,25 +39,41 @@ public class GenericStringTest { public Map[] mixed = null; public Map[][] mixed2 = null; + private static record PlatformTestCase(Class clazz, String expected) {} + public static void main(String... args) throws ReflectiveOperationException { int failures = 0; String[][] nested = {{""}}; int[][] intArray = {{1}}; - Map, String> testCases = - Map.of(int.class, "int", - void.class, "void", - args.getClass(), "java.lang.String[]", - nested.getClass(), "java.lang.String[][]", - intArray.getClass(), "int[][]", - java.lang.Enum.class, "public abstract class java.lang.Enum>", - java.util.Map.class, "public abstract interface java.util.Map", - java.util.EnumMap.class, "public class java.util.EnumMap,V>", - java.util.EventListenerProxy.class, "public abstract class java.util.EventListenerProxy"); - - for (Map.Entry, String> testCase : testCases.entrySet()) { - failures += checkToGenericString(testCase.getKey(), testCase.getValue()); + List platformTestCases = + List.of(new PlatformTestCase(int.class, "int"), + new PlatformTestCase(void.class, "void"), + new PlatformTestCase(args.getClass(), "java.lang.String[]"), + new PlatformTestCase(nested.getClass(), "java.lang.String[][]"), + new PlatformTestCase(intArray.getClass(), "int[][]"), + + new PlatformTestCase(java.lang.Enum.class, + "public abstract class java.lang.Enum>"), + new PlatformTestCase(java.util.Map.class, + "public abstract interface java.util.Map"), + new PlatformTestCase(java.util.EnumMap.class, + "public class java.util.EnumMap,V>"), + new PlatformTestCase(java.util.EventListenerProxy.class, + "public abstract class java.util.EventListenerProxy"), + + // Sealed class + new PlatformTestCase(java.lang.ref.Reference.class, + "public abstract sealed class java.lang.ref.Reference"), + // non-sealed class + new PlatformTestCase(java.lang.ref.WeakReference.class, + "public non-sealed class java.lang.ref.WeakReference") + ); + + for (PlatformTestCase platformTestCase : platformTestCases) { + failures += checkToGenericString(platformTestCase.clazz, + platformTestCase.expected); } Field f = GenericStringTest.class.getDeclaredField("mixed"); @@ -74,7 +89,33 @@ public static void main(String... args) throws ReflectiveOperationException { LocalMap.class, AnEnum.class, AnotherEnum.class, - AValueClass.class)) { + AValueClass.class, + + SealedRootClass.class, + SealedRootClass.ChildA.class, + SealedRootClass.ChildB.class, + SealedRootClass.ChildB.GrandChildAB.class, + SealedRootClass.ChildC.class, + SealedRootClass.ChildC.GrandChildACA.class, + SealedRootClass.ChildC.GrandChildACB.class, + SealedRootClass.ChildC.GrandChildACC.class, + SealedRootClass.ChildC.GrandChildACC.GreatGrandChildACCA.class, + SealedRootClass.ChildC.GrandChildACC.GreatGrandChildACCB.class, + + SealedRootIntf.class, + SealedRootIntf.ChildA.class, + SealedRootIntf.ChildB.class, + SealedRootIntf.ChildB.GrandChildAB.class, + SealedRootIntf.ChildC.class, + SealedRootIntf.ChildC.GrandChildACA.class, + SealedRootIntf.ChildC.GrandChildACB.class, + SealedRootIntf.ChildC.GrandChildACC.class, + SealedRootIntf.ChildC.GrandChildACC.GreatGrandChildACCA.class, + SealedRootIntf.ChildC.GrandChildACC.GreatGrandChildACCB.class, + SealedRootIntf.IntfA.class, + SealedRootIntf.IntfA.IntfAImpl.class, + SealedRootIntf.IntfB.class, + SealedRootIntf.IntfB.IntfAImpl.class)) { failures += checkToGenericString(clazz, clazz.getAnnotation(ExpectedGenericString.class).value()); } @@ -111,10 +152,105 @@ enum AnEnum { FOO; } -@ExpectedGenericString("enum AnotherEnum") +// If an enum class has a specialized enum constant, that is compiled +// by having the enum class as being sealed rather than final. See JLS +// 8.9 Enum Classes. +@ExpectedGenericString("sealed enum AnotherEnum") enum AnotherEnum { BAR{}; } @ExpectedGenericString("final value class AValueClass") value class AValueClass {} + +// Test cases for sealed/non-sealed _class_ hierarchy. +@ExpectedGenericString("sealed class SealedRootClass") +sealed class SealedRootClass + permits + SealedRootClass.ChildA, + SealedRootClass.ChildB, + SealedRootClass.ChildC { + + @ExpectedGenericString("final class SealedRootClass$ChildA") + final class ChildA extends SealedRootClass {} + + @ExpectedGenericString("sealed class SealedRootClass$ChildB") + sealed class ChildB extends SealedRootClass permits SealedRootClass.ChildB.GrandChildAB { + @ExpectedGenericString("final class SealedRootClass$ChildB$GrandChildAB") + final class GrandChildAB extends ChildB {} + } + + @ExpectedGenericString("non-sealed class SealedRootClass$ChildC") + non-sealed class ChildC extends SealedRootClass { + // The subclasses of ChildC do not themselves have to be + // sealed, non-sealed, or final. + @ExpectedGenericString("class SealedRootClass$ChildC$GrandChildACA") + class GrandChildACA extends ChildC {} + + @ExpectedGenericString("final class SealedRootClass$ChildC$GrandChildACB") + final class GrandChildACB extends ChildC {} + + @ExpectedGenericString("sealed class SealedRootClass$ChildC$GrandChildACC") + sealed class GrandChildACC extends ChildC { + @ExpectedGenericString("final class SealedRootClass$ChildC$GrandChildACC$GreatGrandChildACCA") + final class GreatGrandChildACCA extends GrandChildACC {} + + @ExpectedGenericString("non-sealed class SealedRootClass$ChildC$GrandChildACC$GreatGrandChildACCB") + non-sealed class GreatGrandChildACCB extends GrandChildACC {} + } + } +} + +// Test cases for sealed/non-sealed _interface_ hierarchy. +@ExpectedGenericString("abstract sealed interface SealedRootIntf") +sealed interface SealedRootIntf + permits + SealedRootIntf.ChildA, + SealedRootIntf.ChildB, + SealedRootIntf.ChildC, + + SealedRootIntf.IntfA, + SealedRootIntf.IntfB { + + @ExpectedGenericString("public static final class SealedRootIntf$ChildA") + final class ChildA implements SealedRootIntf {} + + @ExpectedGenericString("public static sealed class SealedRootIntf$ChildB") + sealed class ChildB implements SealedRootIntf permits SealedRootIntf.ChildB.GrandChildAB { + @ExpectedGenericString("final class SealedRootIntf$ChildB$GrandChildAB") + final class GrandChildAB extends ChildB {} + } + + @ExpectedGenericString("public static non-sealed class SealedRootIntf$ChildC") + non-sealed class ChildC implements SealedRootIntf { + // The subclasses of ChildC do not themselves have to be + // sealed, non-sealed, or final. + @ExpectedGenericString("class SealedRootIntf$ChildC$GrandChildACA") + class GrandChildACA extends ChildC {} + + @ExpectedGenericString("final class SealedRootIntf$ChildC$GrandChildACB") + final class GrandChildACB extends ChildC {} + + @ExpectedGenericString("sealed class SealedRootIntf$ChildC$GrandChildACC") + sealed class GrandChildACC extends ChildC { + @ExpectedGenericString("final class SealedRootIntf$ChildC$GrandChildACC$GreatGrandChildACCA") + final class GreatGrandChildACCA extends GrandChildACC {} + + @ExpectedGenericString("non-sealed class SealedRootIntf$ChildC$GrandChildACC$GreatGrandChildACCB") + non-sealed class GreatGrandChildACCB extends GrandChildACC {} + } + } + + @ExpectedGenericString("public abstract static sealed interface SealedRootIntf$IntfA") + sealed interface IntfA extends SealedRootIntf { + @ExpectedGenericString("public static non-sealed class SealedRootIntf$IntfA$IntfAImpl") + non-sealed class IntfAImpl implements IntfA {} + } + + @ExpectedGenericString("public abstract static non-sealed interface SealedRootIntf$IntfB") + non-sealed interface IntfB extends SealedRootIntf { + // Check that non-sealing can be allowed with a second superinterface being sealed. + @ExpectedGenericString("public static non-sealed class SealedRootIntf$IntfB$IntfAImpl") + non-sealed class IntfAImpl implements IntfB, IntfA {} + } +} diff --git a/test/jdk/java/lang/ClassLoader/securityManager/ClassLoaderTest.java b/test/jdk/java/lang/ClassLoader/securityManager/ClassLoaderTest.java index 08342caeb75..b25dcda7841 100644 --- a/test/jdk/java/lang/ClassLoader/securityManager/ClassLoaderTest.java +++ b/test/jdk/java/lang/ClassLoader/securityManager/ClassLoaderTest.java @@ -239,7 +239,7 @@ private void execute(String[] args, String status, String msg) throws Exception if (s.contains(" ")) { throw new RuntimeException("No spaces in args");} return !s.isEmpty(); }).toArray(String[]::new); - String out = ProcessTools.executeTestJvm(safeArgs).getOutput(); + String out = ProcessTools.executeTestJava(safeArgs).getOutput(); // Handle response. if ("PASS".equals(status) && out.contains(msg)) { System.out.println("PASS: Expected Result: " + msg); diff --git a/test/jdk/java/lang/RuntimeTests/shutdown/ShutdownHooks.java b/test/jdk/java/lang/RuntimeTests/shutdown/ShutdownHooks.java index 6b2dc7b4dbf..36d3878fb41 100644 --- a/test/jdk/java/lang/RuntimeTests/shutdown/ShutdownHooks.java +++ b/test/jdk/java/lang/RuntimeTests/shutdown/ShutdownHooks.java @@ -61,7 +61,7 @@ public void testShutdownHooks() throws Exception { // Run in a new process in order to evaluate shutdown hook results String[] testCommand = new String[] {"-classpath", TEST_CLASSES, ShutdownHooksProcess.class.getName()}; - ProcessTools.executeTestJvm(testCommand).shouldHaveExitValue(0); + ProcessTools.executeTestJava(testCommand).shouldHaveExitValue(0); String errorMsg = "File exists despite shutdown hook has been run"; assertFalse(Files.exists(TEST_FILE.toPath()), errorMsg); diff --git a/test/jdk/java/lang/ScopedValue/StressStackOverflow.java b/test/jdk/java/lang/ScopedValue/StressStackOverflow.java index a1254c7fef7..863ad189c35 100644 --- a/test/jdk/java/lang/ScopedValue/StressStackOverflow.java +++ b/test/jdk/java/lang/ScopedValue/StressStackOverflow.java @@ -66,7 +66,7 @@ static class TestFailureException extends RuntimeException { TestFailureException(String s) { super(s); } } - static final long DURATION_IN_NANOS = Duration.ofMinutes(2).toNanos(); + static final long DURATION_IN_NANOS = Duration.ofMinutes(1).toNanos(); // Test the ScopedValue recovery mechanism for stack overflows. We implement both Callable // and Runnable interfaces. Which one gets tested depends on the constructor argument. diff --git a/test/jdk/java/lang/String/Chars.java b/test/jdk/java/lang/String/Chars.java index 20cde9d003d..035a7a9de27 100644 --- a/test/jdk/java/lang/String/Chars.java +++ b/test/jdk/java/lang/String/Chars.java @@ -23,8 +23,10 @@ /* * @test - * @bug 8054307 8311906 + * @bug 8054307 8311906 8321514 * @summary test String chars() and codePoints() + * @run main/othervm -XX:+CompactStrings Chars + * @run main/othervm -XX:-CompactStrings Chars */ import java.util.Arrays; @@ -45,6 +47,7 @@ public static void main(String[] args) { } testChars(cc, ccExp); testCharsSubrange(cc, ccExp); + testIntsSubrange(ccExp); testCPs(cc, cpExp); // bmp without surrogates @@ -72,6 +75,7 @@ public static void main(String[] args) { cpExp = Arrays.copyOf(cpExp, k); testChars(cc, ccExp); testCharsSubrange(cc, ccExp); + testIntsSubrange(ccExp); testCPs(cc, cpExp); } } @@ -104,6 +108,27 @@ static void testCharsSubrange(char[] cc, int[] expected) { } } + static void testIntsSubrange(int[] expected) { + int[] offsets = { 7, 31 }; // offsets to test + int LENGTH = 13; + for (int i = 0; i < offsets.length; i++) { + int offset = Math.max(0, offsets[i]); // confine to the input array + int count = Math.min(LENGTH, expected.length - offset); + String str = new String(expected, offset, count); + int[] actual = str.chars().toArray(); + int errOffset = Arrays.mismatch(actual, 0, actual.length, + expected, offset, offset + count); + if (errOffset >= 0) { + System.err.printf("expected[%d] (%d) != actual[%d] (%d)%n", + offset + errOffset, expected[offset + errOffset], + errOffset, actual[errOffset]); + System.err.println("expected: " + Arrays.toString(expected)); + System.err.println("actual: " + Arrays.toString(actual)); + throw new RuntimeException("testIntsSubrange failed!"); + } + } + } + static void testCPs(char[] cc, int[] expected) { String str = new String(cc); if (!Arrays.equals(expected, str.codePoints().toArray())) { diff --git a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java new file mode 100644 index 00000000000..530171e0b64 --- /dev/null +++ b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import java.nio.charset.StandardCharsets; + +/* + * @test + * @bug 8077559 8321180 + * @summary Tests Compact String for maximum size strings + * @requires os.maxMemory >= 8g & vm.bits == 64 + * @requires vm.flagless + * @run junit/othervm -XX:+CompactStrings -Xmx8g MaxSizeUTF16String + * @run junit/othervm -XX:-CompactStrings -Xmx8g MaxSizeUTF16String + * @run junit/othervm -Xcomp -Xmx8g MaxSizeUTF16String + */ + +public class MaxSizeUTF16String { + + private final static int MAX_UTF16_STRING_LENGTH = Integer.MAX_VALUE / 2; + + private final static String EXPECTED_OOME_MESSAGE = "UTF16 String size is"; + private final static String EXPECTED_VM_LIMIT_MESSAGE = "Requested array size exceeds VM limit"; + private final static String UNEXPECTED_JAVA_HEAP_SPACE = "Java heap space"; + + // Create a large UTF-8 byte array with a single non-latin1 character + private static byte[] generateUTF8Data(int byteSize) { + byte[] nonAscii = "\u0100".getBytes(StandardCharsets.UTF_8); + byte[] arr = new byte[byteSize]; + System.arraycopy(nonAscii, 0, arr, 0, nonAscii.length); // non-latin1 at start + return arr; + } + + // Create a large char array with a single non-latin1 character + private static char[] generateCharData(int size) { + char[] nonAscii = "\u0100".toCharArray(); + char[] arr = new char[size]; + System.arraycopy(nonAscii, 0, arr, 0, nonAscii.length); // non-latin1 at start + return arr; + } + + @Test + public void testMaxUTF8() { + // Overly large UTF-8 data with 1 non-latin1 char + final byte[] large_utf8_bytes = generateUTF8Data(MAX_UTF16_STRING_LENGTH + 1); + int[] sizes = new int[] { + MAX_UTF16_STRING_LENGTH + 1, + MAX_UTF16_STRING_LENGTH, + MAX_UTF16_STRING_LENGTH - 1}; + for (int size : sizes) { + System.err.println("Checking max UTF16 string len: " + size); + try { + // Use only part of the UTF-8 byte array + new String(large_utf8_bytes, 0, size, StandardCharsets.UTF_8); + if (size >= MAX_UTF16_STRING_LENGTH) { + fail("Expected OutOfMemoryError with message prefix: " + EXPECTED_OOME_MESSAGE); + } + } catch (OutOfMemoryError ex) { + if (ex.getMessage().equals(UNEXPECTED_JAVA_HEAP_SPACE)) { + // Insufficient heap size + throw ex; + } + if (!ex.getMessage().startsWith(EXPECTED_OOME_MESSAGE) && + !ex.getMessage().startsWith(EXPECTED_VM_LIMIT_MESSAGE)) { + fail("Failed: Not the OutOfMemoryError expected", ex); + } + } + } + } + + @Test + public void testMaxCharArray() { + // Overly large UTF-8 data with 1 non-latin1 char + final char[] large_char_array = generateCharData(MAX_UTF16_STRING_LENGTH + 1); + int[] sizes = new int[]{ + MAX_UTF16_STRING_LENGTH + 1, + MAX_UTF16_STRING_LENGTH, + MAX_UTF16_STRING_LENGTH - 1}; + for (int size : sizes) { + System.err.println("Checking max UTF16 string len: " + size); + try { + // Large char array with 1 non-latin1 char + new String(large_char_array, 0, size); + if (size >= MAX_UTF16_STRING_LENGTH) { + fail("Expected OutOfMemoryError with message prefix: " + EXPECTED_OOME_MESSAGE); + } + } catch (OutOfMemoryError ex) { + if (ex.getMessage().equals(UNEXPECTED_JAVA_HEAP_SPACE)) { + // Insufficient heap size + throw ex; + } + if (!ex.getMessage().startsWith(EXPECTED_OOME_MESSAGE) && + !ex.getMessage().startsWith(EXPECTED_VM_LIMIT_MESSAGE)) { + throw new RuntimeException("Wrong exception message: " + ex.getMessage(), ex); + } + } + } + } +} diff --git a/test/jdk/java/lang/StringBuilder/StringBufferRepeat.java b/test/jdk/java/lang/StringBuilder/StringBufferRepeat.java index 2d1f3c64f60..d78066fb417 100644 --- a/test/jdk/java/lang/StringBuilder/StringBufferRepeat.java +++ b/test/jdk/java/lang/StringBuilder/StringBufferRepeat.java @@ -29,7 +29,7 @@ /** * @test - * @bug 8302323 + * @bug 8302323 8322512 * @summary Test StringBuffer.repeat sanity tests * @run testng/othervm -XX:-CompactStrings StringBufferRepeat * @run testng/othervm -XX:+CompactStrings StringBufferRepeat @@ -129,6 +129,19 @@ public void sanity() { expected = "\u0000\u0000\u0000\u0000\u0000\u0000\u0020\u0020\u0020\u0020\u0020\u0020\u2461\u2462\u2462\u2462\u2462\u2462\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff"; assertEquals(expected, sb.toString()); + // toStringCache + + sb.setLength(0); + sb.toString(); + sb.repeat('*', 5); + expected = "*****"; + assertEquals(sb.toString(), expected); + sb.setLength(0); + sb.toString(); + sb.repeat("*", 5); + assertEquals(sb.toString(), expected); + + } public void exceptions() { diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForImageTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForImageTest.java index b155ba994a6..120bba40e0e 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForImageTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * patched system module, or Xbootclasspath * This test does not require existence of java.logging module, * but require jdk.compiler module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm JDKLoggerForImageTest diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForJDKTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForJDKTest.java index 68bc6fd839b..8c25b062002 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForJDKTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/JDKLoggerForJDKTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * 2. clients are in named/unnamed module, * patched system module, or Xbootclasspath * This test DOES require existence of java.logging module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm JDKLoggerForJDKTest diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/LoggerInImageTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/LoggerInImageTest.java index d3c3ace5a65..2cc510e7f99 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/LoggerInImageTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/LoggerInImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * patched system module, or Xbootclasspath * This test does not require existence of java.logging module, * but require jdk.compiler module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm LoggerInImageTest diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForImageTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForImageTest.java index 2e621597935..df14801c164 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForImageTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ * patched system module, or Xbootclasspath * This test does not require existence of java.logging module, * but require jdk.compiler module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm NamedLoggerForImageTest diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForJDKTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForJDKTest.java index 6abf98c5227..e48cf4786c7 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForJDKTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/NamedLoggerForJDKTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ * patched system module, or Xbootclasspath * This test does not require existence of java.logging module, * but require jdk.compiler module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm NamedLoggerForJDKTest diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForImageTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForImageTest.java index 038c96697cb..26f6246bb85 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForImageTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ * patched system module, or Xbootclasspath * This test does not require existence of java.logging module, * but require jdk.compiler module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm UnnamedLoggerForImageTest diff --git a/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForJDKTest.java b/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForJDKTest.java index b239483b0b7..74a76756162 100644 --- a/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForJDKTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/modules/UnnamedLoggerForJDKTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ * patched system module, or Xbootclasspath * This test does not require existence of java.logging module, * but require jdk.compiler module + * @requires vm.flagless * @library /test/lib * @build Base jdk.test.lib.compiler.CompilerUtils * @run main/othervm UnnamedLoggerForJDKTest diff --git a/test/jdk/java/lang/Thread/DegradedMethodsThrowUOE.java b/test/jdk/java/lang/Thread/ThreadStopTest.java similarity index 57% rename from test/jdk/java/lang/Thread/DegradedMethodsThrowUOE.java rename to test/jdk/java/lang/Thread/ThreadStopTest.java index b16b70eaff0..f3886a3312c 100644 --- a/test/jdk/java/lang/Thread/DegradedMethodsThrowUOE.java +++ b/test/jdk/java/lang/Thread/ThreadStopTest.java @@ -22,60 +22,43 @@ */ /* @test - * @bug 8289610 8249627 8205132 - * @summary Test that Thread stop/suspend/resume throw UOE - * @run junit DegradedMethodsThrowUOE + * @bug 8289610 8249627 8205132 8320532 + * @summary Test that Thread stops throws UOE + * @run junit ThreadStopTest */ import java.time.Duration; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; -import java.util.function.Consumer; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -class DegradedMethodsThrowUOE { +class ThreadStopTest { /** - * Returns a stream of operations on a Thread that should throw UOE. + * Test current thread calling Thread.stop on itself. */ - static Stream> ops() { - return Stream.>of( - Thread::stop, - Thread::suspend, - Thread::resume - ); - } - - /** - * Test degraded method on current thread. - */ - @ParameterizedTest - @MethodSource("ops") - void testCurrentThread(Consumer op) { + @Test + void testCurrentThread() { var thread = Thread.currentThread(); - assertThrows(UnsupportedOperationException.class, () -> op.accept(thread)); + assertThrows(UnsupportedOperationException.class, thread::stop); } /** - * Test degraded method on an unstarted thread. + * Test Thread.stop on an unstarted thread. */ - @ParameterizedTest - @MethodSource("ops") - void testUnstartedThread(Consumer op) { + @Test + void testUnstartedThread() { Thread thread = new Thread(() -> { }); - assertThrows(UnsupportedOperationException.class, () -> op.accept(thread)); + assertThrows(UnsupportedOperationException.class, thread::stop); assertTrue(thread.getState() == Thread.State.NEW); } /** - * Test degraded method on a thread spinning in a loop. + * Test Thread.stop on a thread spinning in a loop. */ - @ParameterizedTest - @MethodSource("ops") - void testRunnableThread(Consumer op) throws Exception { + @Test + void testRunnableThread() throws Exception { AtomicBoolean done = new AtomicBoolean(); Thread thread = new Thread(() -> { while (!done.get()) { @@ -84,7 +67,7 @@ void testRunnableThread(Consumer op) throws Exception { }); thread.start(); try { - assertThrows(UnsupportedOperationException.class, () -> op.accept(thread)); + assertThrows(UnsupportedOperationException.class, thread::stop); // thread should not terminate boolean terminated = thread.join(Duration.ofMillis(500)); @@ -96,11 +79,10 @@ void testRunnableThread(Consumer op) throws Exception { } /** - * Test degraded method on a thread that is parked. + * Test Thread.stop on a thread that is parked. */ - @ParameterizedTest - @MethodSource("ops") - void testWaitingThread(Consumer op) throws Exception { + @Test + void testWaitingThread() throws Exception { Thread thread = new Thread(LockSupport::park); thread.start(); try { @@ -108,7 +90,7 @@ void testWaitingThread(Consumer op) throws Exception { while ((thread.getState() != Thread.State.WAITING)) { Thread.sleep(10); } - assertThrows(UnsupportedOperationException.class, () -> op.accept(thread)); + assertThrows(UnsupportedOperationException.class, thread::stop); assertTrue(thread.getState() == Thread.State.WAITING); } finally { LockSupport.unpark(thread); @@ -117,15 +99,14 @@ void testWaitingThread(Consumer op) throws Exception { } /** - * Test degraded method on a terminated thread. + * Test Thread.stop on a terminated thread. */ - @ParameterizedTest - @MethodSource("ops") - void testTerminatedThread(Consumer op) throws Exception { + @Test + void testTerminatedThread() throws Exception { Thread thread = new Thread(() -> { }); thread.start(); thread.join(); - assertThrows(UnsupportedOperationException.class, () -> op.accept(thread)); + assertThrows(UnsupportedOperationException.class, thread::stop); assertTrue(thread.getState() == Thread.State.TERMINATED); } } diff --git a/test/jdk/java/lang/Thread/virtual/CarrierThreadWaits.java b/test/jdk/java/lang/Thread/virtual/CarrierThreadWaits.java index a94a5de3ce0..d1d5e72204f 100644 --- a/test/jdk/java/lang/Thread/virtual/CarrierThreadWaits.java +++ b/test/jdk/java/lang/Thread/virtual/CarrierThreadWaits.java @@ -40,7 +40,6 @@ import java.lang.management.LockInfo; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicBoolean; @@ -55,38 +54,53 @@ class CarrierThreadWaits { void testCarrierThreadWaiting() throws Exception { try (ForkJoinPool pool = new ForkJoinPool(1)) { var carrierRef = new AtomicReference(); + var vthreadRef = new AtomicReference(); + Executor scheduler = task -> { pool.submit(() -> { - carrierRef.set(Thread.currentThread()); + Thread carrier = Thread.currentThread(); + carrierRef.set(carrier); + Thread vthread = vthreadRef.get(); + + System.err.format("%s run task (%s) ...%n", carrier, vthread); task.run(); + System.err.format("%s task done (%s)%n", carrier, vthread); }); }; // start a virtual thread that spins and remains mounted until "done" - var latch = new CountDownLatch(1); + var started = new AtomicBoolean(); var done = new AtomicBoolean(); Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); - Thread vthread = builder.start(() -> { - latch.countDown(); + Thread vthread = builder.unstarted(() -> { + started.set(true); while (!done.get()) { Thread.onSpinWait(); } }); - - // wait for virtual thread to execute - latch.await(); + vthreadRef.set(vthread); + vthread.start(); try { - long carrierId = carrierRef.get().threadId(); + // wait for virtual thread to start + while (!started.get()) { + Thread.sleep(10); + } + + Thread carrier = carrierRef.get(); + + long carrierId = carrier.threadId(); long vthreadId = vthread.threadId(); // carrier thread should be on WAITING on virtual thread ThreadInfo ti = ManagementFactory.getThreadMXBean().getThreadInfo(carrierId); - assertTrue(ti.getThreadState() == Thread.State.WAITING); - assertEquals(vthread.getClass().getName(), ti.getLockInfo().getClassName()); - assertTrue(ti.getLockInfo().getIdentityHashCode() == System.identityHashCode(vthread)); - assertTrue(ti.getLockOwnerId() == vthreadId); - + Thread.State state = ti.getThreadState(); + LockInfo lockInfo = ti.getLockInfo(); + assertEquals(Thread.State.WAITING, state); + assertNotNull(lockInfo); + assertEquals(vthread.getClass().getName(), lockInfo.getClassName()); + assertEquals(System.identityHashCode(vthread), lockInfo.getIdentityHashCode()); + assertEquals(vthreadId, ti.getLockOwnerId()); } finally { done.set(true); } diff --git a/test/jdk/java/lang/Thread/virtual/GetStackTraceWhenRunnable.java b/test/jdk/java/lang/Thread/virtual/GetStackTraceWhenRunnable.java index 4cf7deecb36..38760eb52a8 100644 --- a/test/jdk/java/lang/Thread/virtual/GetStackTraceWhenRunnable.java +++ b/test/jdk/java/lang/Thread/virtual/GetStackTraceWhenRunnable.java @@ -29,35 +29,34 @@ */ import java.io.IOException; -import java.nio.channels.ClosedSelectorException; -import java.nio.channels.Selector; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; public class GetStackTraceWhenRunnable { public static void main(String[] args) throws Exception { - try (Selector sel = Selector.open()) { - // start thread1 and wait for it to park - Thread thread1 = Thread.startVirtualThread(LockSupport::park); - while (thread1.getState() != Thread.State.WAITING) { - Thread.sleep(20); - } + // start thread1 and wait for it to park + Thread thread1 = Thread.startVirtualThread(LockSupport::park); + while (thread1.getState() != Thread.State.WAITING) { + Thread.sleep(20); + } - // start thread2 to pin the carrier thread - CountDownLatch latch = new CountDownLatch(1); - Thread thread2 = Thread.startVirtualThread(() -> { - latch.countDown(); - try { - sel.select(); - } catch (ClosedSelectorException e) { - // expected - } catch (IOException ioe) { - ioe.printStackTrace(); - } - }); - latch.await(); // wait for thread2 to run + // start thread2 to pin the carrier thread + var started = new AtomicBoolean(); + var done = new AtomicBoolean(); + Thread thread2 = Thread.startVirtualThread(() -> { + started.set(true); + while (!done.get()) { + Thread.onSpinWait(); + } + }); + try { + // wait for thread2 to start + while (!started.get()) { + Thread.sleep(10); + } // unpark thread1 and check that it is "stuck" in the runnable state // (the carrier thread is pinned, no other virtual thread can run) @@ -73,6 +72,10 @@ public static void main(String[] args) throws Exception { for (StackTraceElement e : stack) { System.out.println(e); } + } finally { + done.set(true); + thread2.join(); + thread1.join(); } } diff --git a/test/jdk/java/lang/Thread/virtual/JfrEvents.java b/test/jdk/java/lang/Thread/virtual/JfrEvents.java index 0cdd6a529d1..282a8959fe8 100644 --- a/test/jdk/java/lang/Thread/virtual/JfrEvents.java +++ b/test/jdk/java/lang/Thread/virtual/JfrEvents.java @@ -26,12 +26,12 @@ * @summary Basic test for JFR jdk.VirtualThreadXXX events * @requires vm.continuations * @modules jdk.jfr java.base/java.lang:+open - * @run junit/othervm JfrEvents + * @library /test/lib + * @run junit/othervm --enable-native-access=ALL-UNNAMED JfrEvents */ import java.io.IOException; import java.nio.file.Path; -import java.time.Duration; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -39,20 +39,27 @@ import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; +import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; import jdk.jfr.EventType; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.thread.VThreadPinner; +import jdk.test.lib.thread.VThreadRunner.ThrowingRunnable; 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.junit.jupiter.api.Assertions.*; class JfrEvents { - private static final Object lock = new Object(); /** * Test jdk.VirtualThreadStart and jdk.VirtualThreadEnd events. @@ -85,45 +92,90 @@ void testVirtualThreadStartAndEnd() throws Exception { } } + /** + * Arguments for testVirtualThreadPinned to test jdk.VirtualThreadPinned event. + * [0] label/description + * [1] the operation to park/wait + * [2] the Thread.State when parked/waiting + * [3] the action to unpark/notify the thread + */ + static Stream pinnedCases() { + Object lock = new Object(); + + // park with native frame on stack + var finish1 = new AtomicBoolean(); + var parkWhenPinned = Arguments.of( + "LockSupport.park when pinned", + (ThrowingRunnable) () -> { + VThreadPinner.runPinned(() -> { + while (!finish1.get()) { + LockSupport.park(); + } + }); + }, + Thread.State.WAITING, + (Consumer) t -> { + finish1.set(true); + LockSupport.unpark(t); + } + ); + + // timed park with native frame on stack + var finish2 = new AtomicBoolean(); + var timedParkWhenPinned = Arguments.of( + "LockSupport.parkNanos when pinned", + (ThrowingRunnable) () -> { + VThreadPinner.runPinned(() -> { + while (!finish2.get()) { + LockSupport.parkNanos(Long.MAX_VALUE); + } + }); + }, + Thread.State.TIMED_WAITING, + (Consumer) t -> { + finish2.set(true); + LockSupport.unpark(t); + } + ); + + return Stream.of(parkWhenPinned, timedParkWhenPinned); + } + /** * Test jdk.VirtualThreadPinned event. */ - @Test - void testVirtualThreadPinned() throws Exception { - Runnable[] parkers = new Runnable[] { - () -> LockSupport.park(), - () -> LockSupport.parkNanos(Duration.ofDays(1).toNanos()) - }; + @ParameterizedTest + @MethodSource("pinnedCases") + void testVirtualThreadPinned(String label, + ThrowingRunnable parker, + Thread.State expectedState, + Consumer unparker) throws Exception { try (Recording recording = new Recording()) { recording.enable("jdk.VirtualThreadPinned"); recording.start(); - try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { - for (Runnable parker : parkers) { - // execute parking task in virtual thread - var threadRef = new AtomicReference(); - executor.submit(() -> { - threadRef.set(Thread.currentThread()); - synchronized (lock) { - parker.run(); // should pin carrier - } - }); - - // wait for the task to start and the virtual thread to park - Thread thread; - while ((thread = threadRef.get()) == null) { - Thread.sleep(10); - } + try { + var exception = new AtomicReference(); + var thread = Thread.ofVirtual().start(() -> { try { - Thread.State state = thread.getState(); - while (state != Thread.State.WAITING && state != Thread.State.TIMED_WAITING) { - Thread.sleep(10); - state = thread.getState(); - } - } finally { - LockSupport.unpark(thread); + parker.run(); + } catch (Throwable e) { + exception.set(e); + } + }); + try { + // wait for thread to park/wait + Thread.State state = thread.getState(); + while (state != expectedState) { + assertTrue(state != Thread.State.TERMINATED, thread.toString()); + Thread.sleep(10); + state = thread.getState(); } + } finally { + unparker.accept(thread); + thread.join(); + assertNull(exception.get()); } } finally { recording.stop(); @@ -132,9 +184,9 @@ void testVirtualThreadPinned() throws Exception { Map events = sumEvents(recording); System.err.println(events); - // should have a pinned event for each park + // should have at least one pinned event int pinnedCount = events.getOrDefault("jdk.VirtualThreadPinned", 0); - assertEquals(parkers.length, pinnedCount); + assertTrue(pinnedCount >= 1, "Expected one or more events"); } } diff --git a/test/jdk/java/lang/Thread/virtual/WaitNotify.java b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java similarity index 81% rename from test/jdk/java/lang/Thread/virtual/WaitNotify.java rename to test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java index bc7b36b39be..1320cc8f15f 100644 --- a/test/jdk/java/lang/Thread/virtual/WaitNotify.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java @@ -24,8 +24,9 @@ /** * @test * @summary Test virtual threads using Object.wait/notifyAll + * @modules java.base/java.lang:+open * @library /test/lib - * @run junit WaitNotify + * @run junit MonitorWaitNotify */ import java.util.concurrent.Semaphore; @@ -34,7 +35,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -class WaitNotify { +class MonitorWaitNotify { /** * Test virtual thread waits, notified by platform thread. @@ -84,24 +85,31 @@ void testWaitNotify2() throws Exception { */ @Test void testWaitNotify3() throws Exception { - var lock = new Object(); - var ready = new Semaphore(0); - var thread1 = Thread.ofVirtual().start(() -> { - synchronized (lock) { - ready.release(); - try { - lock.wait(); - } catch (InterruptedException e) { } - } - }); - var thread2 = Thread.ofVirtual().start(() -> { - ready.acquireUninterruptibly(); - synchronized (lock) { - lock.notifyAll(); - } - }); - thread1.join(); - thread2.join(); + // need at least two carrier threads due to pinning + int previousParallelism = VThreadRunner.ensureParallelism(2); + try { + var lock = new Object(); + var ready = new Semaphore(0); + var thread1 = Thread.ofVirtual().start(() -> { + synchronized (lock) { + ready.release(); + try { + lock.wait(); + } catch (InterruptedException e) { } + } + }); + var thread2 = Thread.ofVirtual().start(() -> { + ready.acquireUninterruptibly(); + synchronized (lock) { + lock.notifyAll(); + } + }); + thread1.join(); + thread2.join(); + } finally { + // restore + VThreadRunner.setParallelism(previousParallelism); + } } /** diff --git a/test/jdk/java/lang/Thread/virtual/StackTraces.java b/test/jdk/java/lang/Thread/virtual/StackTraces.java index fb5c40dc4e9..cb1877090fe 100644 --- a/test/jdk/java/lang/Thread/virtual/StackTraces.java +++ b/test/jdk/java/lang/Thread/virtual/StackTraces.java @@ -23,7 +23,7 @@ /** * @test - * @summary Test stack traces in exceptions and stack frames waslked by the StackWalker + * @summary Test stack traces in exceptions and stack frames walked by the StackWalker * API do not include the carrier stack frames * @requires vm.continuations * @modules java.management diff --git a/test/jdk/java/lang/Thread/virtual/ThreadAPI.java b/test/jdk/java/lang/Thread/virtual/ThreadAPI.java index 663da9126d6..b1ccb21910a 100644 --- a/test/jdk/java/lang/Thread/virtual/ThreadAPI.java +++ b/test/jdk/java/lang/Thread/virtual/ThreadAPI.java @@ -27,7 +27,7 @@ * @summary Test Thread API with virtual threads * @modules java.base/java.lang:+open * @library /test/lib - * @run junit ThreadAPI + * @run junit/othervm --enable-native-access=ALL-UNNAMED ThreadAPI */ /* @@ -35,7 +35,8 @@ * @requires vm.continuations * @modules java.base/java.lang:+open * @library /test/lib - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations ThreadAPI + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations + * --enable-native-access=ALL-UNNAMED ThreadAPI */ import java.time.Duration; @@ -61,6 +62,7 @@ import java.nio.channels.Selector; import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadPinner; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.AfterAll; @@ -273,64 +275,6 @@ void testStop2() throws Exception { } } - /** - * Test Thread::suspend from current thread. - */ - @Test - void testSuspend1() throws Exception { - VThreadRunner.run(() -> { - Thread t = Thread.currentThread(); - assertThrows(UnsupportedOperationException.class, t::suspend); - }); - } - - /** - * Test Thread::suspend from another thread. - */ - @Test - void testSuspend2() throws Exception { - var thread = Thread.ofVirtual().start(() -> { - try { - Thread.sleep(20*1000); - } catch (InterruptedException e) { } - }); - try { - assertThrows(UnsupportedOperationException.class, () -> thread.suspend()); - } finally { - thread.interrupt(); - thread.join(); - } - } - - /** - * Test Thread::resume from current thread. - */ - @Test - void testResume1() throws Exception { - VThreadRunner.run(() -> { - Thread t = Thread.currentThread(); - assertThrows(UnsupportedOperationException.class, t::resume); - }); - } - - /** - * Test Thread::resume from another thread. - */ - @Test - void testResume2() throws Exception { - var thread = Thread.ofVirtual().start(() -> { - try { - Thread.sleep(20*1000); - } catch (InterruptedException e) { } - }); - try { - assertThrows(UnsupportedOperationException.class, () -> thread.resume()); - } finally { - thread.interrupt(); - thread.join(); - } - } - /** * Test Thread.join before thread starts, platform thread invokes join. */ @@ -755,11 +699,11 @@ void testJoin32() throws Exception { void testJoin33() throws Exception { AtomicBoolean done = new AtomicBoolean(); Thread thread = Thread.ofVirtual().start(() -> { - synchronized (lock) { + VThreadPinner.runPinned(() -> { while (!done.get()) { LockSupport.parkNanos(Duration.ofMillis(20).toNanos()); } - } + }); }); try { assertFalse(thread.join(Duration.ofMillis(100))); @@ -1136,7 +1080,7 @@ void testSetDaemon2() throws Exception { } /** - * Test Thread.yield releases thread when not pinned. + * Test Thread.yield releases carrier thread. */ @Test void testYield1() throws Exception { @@ -1164,7 +1108,7 @@ void testYield1() throws Exception { } /** - * Test Thread.yield when thread is pinned. + * Test Thread.yield when thread is pinned by native frame. */ @Test void testYield2() throws Exception { @@ -1179,10 +1123,10 @@ void testYield2() throws Exception { list.add("B"); }); child.start(); - synchronized (lock) { + VThreadPinner.runPinned(() -> { Thread.yield(); // pinned so will be a no-op list.add("A"); - } + }); try { child.join(); } catch (InterruptedException e) { } }); thread.start(); @@ -1192,7 +1136,7 @@ void testYield2() throws Exception { } /** - * Test that Thread.yield does not consume the thread's parking permit. + * Test Thread.yield does not consume the thread's parking permit. */ @Test void testYield3() throws Exception { @@ -1205,7 +1149,7 @@ void testYield3() throws Exception { } /** - * Test that Thread.yield does not make available the thread's parking permit. + * Test Thread.yield does not make available the thread's parking permit. */ @Test void testYield4() throws Exception { @@ -1406,11 +1350,9 @@ void testSleep7() throws Exception { */ @Test void testSleep8() throws Exception { - VThreadRunner.run(() -> { + VThreadPinner.runPinned(() -> { long start = millisTime(); - synchronized (lock) { - Thread.sleep(1000); - } + Thread.sleep(1000); expectDuration(start, /*min*/900, /*max*/20_000); }); } @@ -1424,9 +1366,9 @@ void testSleep9() throws Exception { Thread me = Thread.currentThread(); me.interrupt(); try { - synchronized (lock) { + VThreadPinner.runPinned(() -> { Thread.sleep(2000); - } + }); fail("sleep not interrupted"); } catch (InterruptedException e) { // expected @@ -1444,9 +1386,9 @@ void testSleep10() throws Exception { Thread t = Thread.currentThread(); scheduleInterrupt(t, 100); try { - synchronized (lock) { + VThreadPinner.runPinned(() -> { Thread.sleep(20 * 1000); - } + }); fail("sleep not interrupted"); } catch (InterruptedException e) { // interrupt status should be cleared @@ -1579,8 +1521,7 @@ void testContextClassLoader5() throws Exception { @Test void testUncaughtExceptionHandler1() throws Exception { class FooException extends RuntimeException { } - var exception = new AtomicReference(); - Thread.UncaughtExceptionHandler handler = (thread, exc) -> exception.set(exc); + var handler = new CapturingUHE(); Thread thread = Thread.ofVirtual().start(() -> { Thread me = Thread.currentThread(); assertTrue(me.getUncaughtExceptionHandler() == me.getThreadGroup()); @@ -1589,7 +1530,8 @@ class FooException extends RuntimeException { } throw new FooException(); }); thread.join(); - assertTrue(exception.get() instanceof FooException); + assertInstanceOf(FooException.class, handler.exception()); + assertEquals(thread, handler.thread()); assertNull(thread.getUncaughtExceptionHandler()); } @@ -1599,8 +1541,7 @@ class FooException extends RuntimeException { } @Test void testUncaughtExceptionHandler2() throws Exception { class FooException extends RuntimeException { } - var exception = new AtomicReference(); - Thread.UncaughtExceptionHandler handler = (thread, exc) -> exception.set(exc); + var handler = new CapturingUHE(); Thread.UncaughtExceptionHandler savedHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(handler); Thread thread; @@ -1611,25 +1552,61 @@ class FooException extends RuntimeException { } }); thread.join(); } finally { - Thread.setDefaultUncaughtExceptionHandler(savedHandler); + Thread.setDefaultUncaughtExceptionHandler(savedHandler); // restore } - assertTrue(exception.get() instanceof FooException); + assertInstanceOf(FooException.class, handler.exception()); + assertEquals(thread, handler.thread()); assertNull(thread.getUncaughtExceptionHandler()); } /** - * Test no UncaughtExceptionHandler set. + * Test Thread and default UncaughtExceptionHandler set. */ @Test void testUncaughtExceptionHandler3() throws Exception { class FooException extends RuntimeException { } - Thread thread = Thread.ofVirtual().start(() -> { - throw new FooException(); - }); - thread.join(); + var defaultHandler = new CapturingUHE(); + var threadHandler = new CapturingUHE(); + Thread.UncaughtExceptionHandler savedHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(defaultHandler); + Thread thread; + try { + thread = Thread.ofVirtual().start(() -> { + Thread me = Thread.currentThread(); + assertTrue(me.getUncaughtExceptionHandler() == me.getThreadGroup()); + me.setUncaughtExceptionHandler(threadHandler); + assertTrue(me.getUncaughtExceptionHandler() == threadHandler); + throw new FooException(); + }); + thread.join(); + } finally { + Thread.setDefaultUncaughtExceptionHandler(savedHandler); // restore + } + assertInstanceOf(FooException.class, threadHandler.exception()); + assertNull(defaultHandler.exception()); + assertEquals(thread, threadHandler.thread()); assertNull(thread.getUncaughtExceptionHandler()); } + /** + * Test no Thread or default UncaughtExceptionHandler set. + */ + @Test + void testUncaughtExceptionHandler4() throws Exception { + Thread.UncaughtExceptionHandler savedHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(null); + try { + class FooException extends RuntimeException { } + Thread thread = Thread.ofVirtual().start(() -> { + throw new FooException(); + }); + thread.join(); + assertNull(thread.getUncaughtExceptionHandler()); + } finally { + Thread.setDefaultUncaughtExceptionHandler(savedHandler); + } + } + /** * Test Thread::threadId and getId. */ @@ -2064,10 +2041,76 @@ void testGetStackTrace5() throws Exception { } /** - * Test Thread::getStackTrace on terminated thread. + * Test Thread::getStackTrace on timed-parked thread. */ @Test void testGetStackTrace6() throws Exception { + var thread = Thread.ofVirtual().start(() -> { + LockSupport.parkNanos(Long.MAX_VALUE); + }); + await(thread, Thread.State.TIMED_WAITING); + try { + StackTraceElement[] stack = thread.getStackTrace(); + assertTrue(contains(stack, "LockSupport.parkNanos")); + } finally { + LockSupport.unpark(thread); + thread.join(); + } + } + + /** + * Test Thread::getStackTrace on parked thread that is pinned. + */ + @Test + void testGetStackTrace7() throws Exception { + AtomicBoolean done = new AtomicBoolean(); + var thread = Thread.ofVirtual().start(() -> { + VThreadPinner.runPinned(() -> { + while (!done.get()) { + LockSupport.park(); + } + }); + }); + await(thread, Thread.State.WAITING); + try { + StackTraceElement[] stack = thread.getStackTrace(); + assertTrue(contains(stack, "LockSupport.park")); + } finally { + done.set(true); + LockSupport.unpark(thread); + thread.join(); + } + } + + /** + * Test Thread::getStackTrace on timed-parked thread that is pinned. + */ + @Test + void testGetStackTrace8() throws Exception { + AtomicBoolean done = new AtomicBoolean(); + var thread = Thread.ofVirtual().start(() -> { + VThreadPinner.runPinned(() -> { + while (!done.get()) { + LockSupport.parkNanos(Long.MAX_VALUE); + } + }); + }); + await(thread, Thread.State.TIMED_WAITING); + try { + StackTraceElement[] stack = thread.getStackTrace(); + assertTrue(contains(stack, "LockSupport.parkNanos")); + } finally { + done.set(true); + LockSupport.unpark(thread); + thread.join(); + } + } + + /** + * Test Thread::getStackTrace on terminated thread. + */ + @Test + void testGetStackTrace9() throws Exception { var thread = Thread.ofVirtual().start(() -> { }); thread.join(); StackTraceElement[] stack = thread.getStackTrace(); @@ -2234,7 +2277,7 @@ void testEnumerate1() throws Exception { ThreadGroup vgroup = Thread.currentThread().getThreadGroup(); Thread[] threads = new Thread[100]; int n = vgroup.enumerate(threads, /*recurse*/false); - assertTrue(n == 0); + assertFalse(Arrays.stream(threads, 0, n).anyMatch(Thread::isVirtual)); }); } @@ -2347,6 +2390,33 @@ void testToString4() throws Exception { assertTrue(thread.toString().contains("fred")); } + /** + * Thread.UncaughtExceptionHandler that captures the first exception thrown. + */ + private static class CapturingUHE implements Thread.UncaughtExceptionHandler { + Thread thread; + Throwable exception; + @Override + public void uncaughtException(Thread t, Throwable e) { + synchronized (this) { + if (thread == null) { + this.thread = t; + this.exception = e; + } + } + } + Thread thread() { + synchronized (this) { + return thread; + } + } + Throwable exception() { + synchronized (this) { + return exception; + } + } + } + /** * Waits for the given thread to reach a given state. */ diff --git a/test/jdk/java/lang/Thread/virtual/TracePinnedThreads.java b/test/jdk/java/lang/Thread/virtual/TracePinnedThreads.java index 01fbdc76d49..5db29c631a3 100644 --- a/test/jdk/java/lang/Thread/virtual/TracePinnedThreads.java +++ b/test/jdk/java/lang/Thread/virtual/TracePinnedThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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 - * @bug 8284161 8289284 + * @bug 8284161 8289284 8322846 * @summary Basic test of debugging option to trace pinned threads * @requires vm.continuations * @library /test/lib @@ -34,6 +34,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.time.Duration; +import java.util.concurrent.Executors; import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadRunner; @@ -67,8 +68,8 @@ void testPinnedCausedBySynchronizedBlock() throws Exception { park(); } }); + assertContains(output, "reason:MONITOR"); assertContains(output, "<== monitors:1"); - assertDoesNotContain(output, "(Native Method)"); } /** @@ -78,8 +79,68 @@ void testPinnedCausedBySynchronizedBlock() throws Exception { void testPinnedCausedByNativeMethod() throws Exception { System.loadLibrary("TracePinnedThreads"); String output = run(() -> invokePark()); + assertContains(output, "reason:NATIVE"); assertContains(output, "(Native Method)"); - assertDoesNotContain(output, "<== monitors"); + } + + /** + * Test parking in class initializer. + */ + @Test + void testPinnedCausedByClassInitializer() throws Exception { + class C { + static { + park(); + } + } + String output = run(C::new); + assertContains(output, "reason:NATIVE"); + assertContains(output, ""); + } + + /** + * Test contention writing to System.out when pinned. The test creates four threads + * that write to System.out when pinned, this is enough to potentially deadlock + * without the changes in JDK-8322846. + */ + @Test + void testContention() throws Exception { + // use several classes to avoid duplicate stack traces + class C1 { + synchronized void print() { + System.out.println("hello"); + } + } + class C2 { + synchronized void print() { + System.out.println("hello"); + } + } + class C3 { + synchronized void print() { + System.out.println("hello"); + } + } + class C4 { + synchronized void print() { + System.out.println("hello"); + } + } + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + executor.submit(() -> { + new C1().print(); + }); + executor.submit(() -> { + new C2().print(); + }); + executor.submit(() -> { + new C3().print(); + }); + executor.submit(() -> { + new C4().print(); + }); + } } /** diff --git a/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java b/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java index a4bccd47265..1ae73b280cb 100644 --- a/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java +++ b/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java @@ -25,15 +25,18 @@ * @test * @summary Test parking when pinned and emitting the JFR VirtualThreadPinnedEvent throws * @modules java.base/jdk.internal.event + * @library /test/lib * @compile/module=java.base jdk/internal/event/VirtualThreadPinnedEvent.java - * @run junit VirtualThreadPinnedEventThrows + * @run junit/othervm --enable-native-access=ALL-UNNAMED VirtualThreadPinnedEventThrows */ import java.lang.ref.Reference; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; import jdk.internal.event.VirtualThreadPinnedEvent; +import jdk.test.lib.thread.VThreadPinner; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -82,29 +85,31 @@ void testVirtualThreadPinnedEventCommitThrows() throws Exception { * Test parking a virtual thread when pinned. */ private void testParkWhenPinned() throws Exception { - Object lock = new Object(); + var exception = new AtomicReference(); + var done = new AtomicBoolean(); + Thread thread = Thread.startVirtualThread(() -> { + try { + VThreadPinner.runPinned(() -> { + while (!done.get()) { + LockSupport.park(); + } + }); + } catch (Throwable e) { + exception.set(e); + } + }); try { - var completed = new AtomicBoolean(); - Thread thread = Thread.startVirtualThread(() -> { - synchronized (lock) { - LockSupport.park(); - completed.set(true); - } - }); - // wait for thread to park Thread.State state; while ((state = thread.getState()) != Thread.State.WAITING) { assertTrue(state != Thread.State.TERMINATED); Thread.sleep(10); } - - // unpark and check that thread completed without exception + } finally { + done.set(true); LockSupport.unpark(thread); thread.join(); - assertTrue(completed.get()); - } finally { - Reference.reachabilityFence(lock); } + assertNull(exception.get()); } } diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java new file mode 100644 index 00000000000..1790ef5eeac --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 8322818 + * @summary Stress test Thread.getStackTrace on a virtual thread that is pinned + * @requires vm.debug != true + * @run main GetStackTraceALotWhenPinned 25000 + */ + +/* + * @test + * @requires vm.debug == true + * @run main/timeout=300 GetStackTraceALotWhenPinned 10000 + */ + +import java.time.Instant; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; + +public class GetStackTraceALotWhenPinned { + + public static void main(String[] args) throws Exception { + var counter = new AtomicInteger(Integer.parseInt(args[0])); + + // Start a virtual thread that loops doing Thread.yield and parking while pinned. + // This loop creates the conditions for the main thread to sample the stack trace + // as it transitions from being unmounted to parking while pinned. + var thread = Thread.startVirtualThread(() -> { + boolean timed = false; + while (counter.decrementAndGet() > 0) { + Thread.yield(); + synchronized (GetStackTraceALotWhenPinned.class) { + if (timed) { + LockSupport.parkNanos(Long.MAX_VALUE); + } else { + LockSupport.park(); + } + } + timed = !timed; + } + }); + + long lastTimestamp = System.currentTimeMillis(); + while (thread.isAlive()) { + thread.getStackTrace(); + LockSupport.unpark(thread); + long currentTime = System.currentTimeMillis(); + if ((currentTime - lastTimestamp) > 500) { + System.out.format("%s %d remaining ...%n", Instant.now(), counter.get()); + lastTimestamp = currentTime; + } + } + } +} diff --git a/test/jdk/java/lang/Thread/virtual/stress/PinALot.java b/test/jdk/java/lang/Thread/virtual/stress/PinALot.java index 7bfce95b5c2..a420ebb330e 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/PinALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/PinALot.java @@ -25,13 +25,15 @@ * @test * @summary Stress test timed park when pinned * @requires vm.debug != true - * @run main PinALot 500000 + * @library /test/lib + * @run main/othervm --enable-native-access=ALL-UNNAMED PinALot 500000 */ /* * @test * @requires vm.debug == true - * @run main/othervm/timeout=300 PinALot 200000 + * @library /test/lib + * @run main/othervm/timeout=300 --enable-native-access=ALL-UNNAMED PinALot 200000 */ import java.time.Duration; @@ -39,9 +41,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; -public class PinALot { +import jdk.test.lib.thread.VThreadPinner; - static final Object lock = new Object(); +public class PinALot { public static void main(String[] args) throws Exception { int iterations = 1_000_000; @@ -53,11 +55,11 @@ public static void main(String[] args) throws Exception { AtomicInteger count = new AtomicInteger(); Thread thread = Thread.ofVirtual().start(() -> { - synchronized (lock) { + VThreadPinner.runPinned(() -> { while (count.incrementAndGet() < ITERATIONS) { LockSupport.parkNanos(1); } - } + }); }); boolean terminated; diff --git a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java index fb4adbb25f2..ee45fc827b0 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java +++ b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java @@ -26,7 +26,7 @@ * @summary Stress test virtual threads with a variation of the Skynet 1M benchmark * @requires vm.continuations * @requires !vm.debug | vm.gc != "Z" - * @run main/othervm/timeout=300 -Xmx1g Skynet + * @run main/othervm/timeout=300 -Xmx1500m Skynet */ /* @@ -35,7 +35,7 @@ * @requires vm.gc.ZSinglegen * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions * -XX:+UseZGC -XX:-ZGenerational - * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1g Skynet + * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1500m Skynet */ /* @@ -44,7 +44,7 @@ * @requires vm.gc.ZGenerational * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions * -XX:+UseZGC -XX:+ZGenerational - * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1g Skynet + * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1500m Skynet */ import java.util.concurrent.BlockingQueue; diff --git a/test/jdk/java/lang/ThreadGroup/BasicTests.java b/test/jdk/java/lang/ThreadGroup/BasicTests.java index 2c6cf6dbca7..ccd8a0153c3 100644 --- a/test/jdk/java/lang/ThreadGroup/BasicTests.java +++ b/test/jdk/java/lang/ThreadGroup/BasicTests.java @@ -732,24 +732,6 @@ void testList() { group.list(); } - @Test - void testSuspend() { - ThreadGroup group = new ThreadGroup("foo"); - assertThrows(UnsupportedOperationException.class, () -> group.suspend()); - } - - @Test - void testResume() { - ThreadGroup group = new ThreadGroup("foo"); - assertThrows(UnsupportedOperationException.class, () -> group.resume()); - } - - @Test - void testStop() { - ThreadGroup group = new ThreadGroup("foo"); - assertThrows(UnsupportedOperationException.class, () -> group.stop()); - } - @Test void testNull1() { assertThrows(NullPointerException.class, diff --git a/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java b/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java index f97cfcec243..051a31dcb1b 100644 --- a/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java +++ b/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java @@ -64,6 +64,7 @@ * -Djdk.httpclient.HttpClient.log=frames,ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true * -Dsun.net.httpserver.idleInterval=50000 + * -Djdk.tracePinnedThreads=full * HttpClientLocalAddrTest * * @run testng/othervm/java.security.policy=httpclient-localaddr-security.policy diff --git a/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java b/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java index 7d369d7ddd9..794ede84a92 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java +++ b/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8236246 * @modules java.base/sun.nio.ch - * @run testng InterruptibleOrNot + * @run junit InterruptibleOrNot * @summary Test SelectorProviderImpl.openDatagramChannel(boolean) to create * DatagramChannel objects that optionally support interrupt */ @@ -40,152 +40,178 @@ import java.nio.channels.ClosedByInterruptException; import java.nio.channels.DatagramChannel; import java.time.Duration; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.Arrays; import sun.nio.ch.DefaultSelectorProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.function.Executable; +import static org.junit.jupiter.api.Assertions.*; -@Test public class InterruptibleOrNot { + // DatagramChannel implementation class + private static String dcImplClassName; - public void testInterruptBeforeInterruptibleReceive() throws Exception { - testInterruptBeforeReceive(true); - } - - public void testInterruptDuringInterruptibleReceive() throws Exception { - testInterruptDuringReceive(true); - } - - public void testInterruptBeforeUninterruptibleReceive() throws Exception { - testInterruptBeforeReceive(false); - } - - public void testInterruptDuringUninterruptibleReceive() throws Exception { - testInterruptDuringReceive(false); - } - - public void testInterruptBeforeInterruptibleSend() throws Exception { - testInterruptBeforeSend(true); + @BeforeAll + static void setup() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + dcImplClassName = dc.getClass().getName(); + } } - public void testInterruptBeforeUninterruptibleSend() throws Exception { - testInterruptBeforeSend(false); + /** + * Call DatagramChannel.receive with the interrupt status set, the DatagramChannel + * is interruptible. + */ + @Test + public void testInterruptBeforeInterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + Thread.currentThread().interrupt(); + assertThrows(ClosedByInterruptException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt status + } } /** - * Test invoking DatagramChannel receive with interrupt status set + * Test interrupting a thread blocked in DatagramChannel.receive, the DatagramChannel + * is interruptible. */ - static void testInterruptBeforeReceive(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timeout = scheduleClose(dc, Duration.ofSeconds(2)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - Thread.currentThread().interrupt(); - assertThrows(expectedException(interruptible), () -> dc.receive(buf)); - } finally { - timeout.cancel(false); - } + @Test + public void testInterruptDuringInterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + Thread thread = Thread.currentThread(); + onReceive(thread::interrupt); + assertThrows(ClosedByInterruptException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Test Thread.interrupt when target thread is blocked in DatagramChannel receive + * Call DatagramChannel.receive with the interrupt status set, the DatagramChannel + * is not interruptible. */ - static void testInterruptDuringReceive(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timerTask = scheduleClose(dc, Duration.ofSeconds(5)); - Future interruptTask = scheduleInterrupt(Thread.currentThread(), Duration.ofSeconds(1)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - assertThrows(expectedException(interruptible), () -> dc.receive(buf)); - } finally { - timerTask.cancel(false); - interruptTask.cancel(false); - } + @Test + public void testInterruptBeforeUninterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(false)) { + ByteBuffer buf = ByteBuffer.allocate(100); + onReceive(() -> { + // close the channel after a delay to ensure receive wakes up + Thread.sleep(1000); + dc.close(); + }); + Thread.currentThread().interrupt(); + assertThrows(AsynchronousCloseException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Test invoking DatagramChannel send with interrupt status set + * Test interrupting a thread blocked in DatagramChannel.receive, the DatagramChannel + * is not interruptible. */ - static void testInterruptBeforeSend(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timeout = scheduleClose(dc, Duration.ofSeconds(2)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - SocketAddress target = dc.getLocalAddress(); - Thread.currentThread().interrupt(); - if (interruptible) { - assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target)); - } else { - int n = dc.send(buf, target); - assertTrue(n == 100); - } - } finally { - timeout.cancel(false); - } + @Test + public void testInterruptDuringUninterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + + Thread thread = Thread.currentThread(); + onReceive(() -> { + // interrupt should not cause the receive to wakeup + thread.interrupt(); + + // close the channel after a delay to ensure receive wakes up + Thread.sleep(1000); + dc.close(); + }); + assertThrows(AsynchronousCloseException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Creates a DatagramChannel that is interruptible or not. + * Call DatagramChannel.send with the interrupt status set, the DatagramChannel + * is interruptible. */ - static DatagramChannel openDatagramChannel(boolean interruptible) throws IOException { - if (interruptible) { - return DatagramChannel.open(); - } else { - return DefaultSelectorProvider.get().openUninterruptibleDatagramChannel(); + @Test + public void testInterruptBeforeInterruptibleSend() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + SocketAddress target = dc.getLocalAddress(); + Thread.currentThread().interrupt(); + assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target)); + assertFalse(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt } } /** - * Expect ClosedByInterruptException if interruptible. + * Call DatagramChannel.send with the interrupt status set, the DatagramChannel + * is not interruptible. */ - static Class expectedException(boolean expectInterrupt) { - if (expectInterrupt) { - return ClosedByInterruptException.class; - } else { - return AsynchronousCloseException.class; + @Test + public void testInterruptBeforeUninterruptibleSend() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(false)) { + ByteBuffer buf = ByteBuffer.allocate(100); + SocketAddress target = dc.getLocalAddress(); + Thread.currentThread().interrupt(); + int n = dc.send(buf, target); + assertEquals(100, n); + assertTrue(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt status } } /** - * Schedule the given object to be closed. + * Creates a DatagramChannel that is interruptible or not, and bound to the loopback + * address. */ - static Future scheduleClose(Closeable c, Duration timeout) { - long nanos = TimeUnit.NANOSECONDS.convert(timeout); - return STPE.schedule(() -> { - c.close(); - return null; - }, nanos, TimeUnit.NANOSECONDS); + static DatagramChannel boundDatagramChannel(boolean interruptible) throws IOException { + DatagramChannel dc; + if (interruptible) { + dc = DatagramChannel.open(); + } else { + dc = DefaultSelectorProvider.get().openUninterruptibleDatagramChannel(); + } + try { + dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + } catch (IOException ioe) { + dc.close(); + throw ioe; + } + return dc; } /** - * Schedule the given thread to be interrupted. + * Runs the given action when the current thread is sampled in DatagramChannel.receive. */ - static Future scheduleInterrupt(Thread t, Duration timeout) { - long nanos = TimeUnit.NANOSECONDS.convert(timeout); - return STPE.schedule(t::interrupt, nanos, TimeUnit.NANOSECONDS); + static void onReceive(Executable action) { + Thread target = Thread.currentThread(); + Thread.ofPlatform().daemon().start(() -> { + try { + boolean found = false; + while (!found) { + Thread.sleep(20); + StackTraceElement[] stack = target.getStackTrace(); + found = Arrays.stream(stack) + .anyMatch(e -> dcImplClassName.equals(e.getClassName()) + && "receive".equals(e.getMethodName())); + } + action.execute(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + }); } - - static final ScheduledExecutorService STPE = Executors.newScheduledThreadPool(0); } diff --git a/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java b/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java index 630a1ef88b8..de8b48ec22d 100644 --- a/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java +++ b/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -411,9 +411,7 @@ public void testInterruptDuringSelect() throws Exception { // select(Consumer, timeout) try (Selector sel = Selector.open()) { scheduleInterrupt(Thread.currentThread(), 1, SECONDS); - long start = System.currentTimeMillis(); int n = sel.select(k -> assertTrue(false), 60*1000); - long duration = System.currentTimeMillis() - start; assertTrue(n == 0); assertTrue(Thread.currentThread().isInterrupted()); assertTrue(sel.isOpen()); diff --git a/test/jdk/java/nio/channels/SocketChannel/SendUrgentData.java b/test/jdk/java/nio/channels/SocketChannel/SendUrgentData.java index b861e62a267..4fb88c265a1 100644 --- a/test/jdk/java/nio/channels/SocketChannel/SendUrgentData.java +++ b/test/jdk/java/nio/channels/SocketChannel/SendUrgentData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,9 @@ public static void main(String[] args) throws Exception { boolean inline = false; if (args.length > 0 && args[0].equals("-server")) { System.out.println(serverThread.getAddress()); - Thread.currentThread().suspend(); + while (true) { + Thread.sleep(60_000); + } } else { if (args.length > 0 && args[0].equals("-client")) { host = args[1]; diff --git a/test/jdk/java/security/Policy/ExtensiblePolicy/ExtensiblePolicyWithJarTest.java b/test/jdk/java/security/Policy/ExtensiblePolicy/ExtensiblePolicyWithJarTest.java index 8fdd7878639..fdbe44fb03c 100644 --- a/test/jdk/java/security/Policy/ExtensiblePolicy/ExtensiblePolicyWithJarTest.java +++ b/test/jdk/java/security/Policy/ExtensiblePolicy/ExtensiblePolicyWithJarTest.java @@ -94,7 +94,7 @@ public static void main(String args[]) throws Throwable { "-Djava.security.manager", "-Djava.security.policy=" + POL, "ExtensiblePolicyTest_orig$TestMain"}; - ProcessTools.executeTestJvm(cmd).shouldHaveExitValue(0); + ProcessTools.executeTestJava(cmd).shouldHaveExitValue(0); } catch (Exception ex) { System.out.println("ExtensiblePolicyWithJarTest Failed"); } diff --git a/test/jdk/java/security/Policy/SignedJar/SignedJarTest.java b/test/jdk/java/security/Policy/SignedJar/SignedJarTest.java index c93337d73d0..cd06cc15691 100644 --- a/test/jdk/java/security/Policy/SignedJar/SignedJarTest.java +++ b/test/jdk/java/security/Policy/SignedJar/SignedJarTest.java @@ -121,7 +121,7 @@ public static void main(String args[]) throws Throwable { System.out.println("Test Case 1"); //copy policy file into current directory String[] cmd = constructCMD("first.jar", POLICY1, "false", "true"); - ProcessTools.executeTestJvm(cmd).shouldHaveExitValue(0); + ProcessTools.executeTestJava(cmd).shouldHaveExitValue(0); //test case 2, test with both.jar //setIO permission granted to code that was signed by first signer @@ -131,7 +131,7 @@ public static void main(String args[]) throws Throwable { //Expect no AccessControlException System.out.println("Test Case 2"); cmd = constructCMD("both.jar", POLICY1, "false", "false"); - ProcessTools.executeTestJvm(cmd).shouldHaveExitValue(0); + ProcessTools.executeTestJava(cmd).shouldHaveExitValue(0); //test case 3 //setIO permission granted to code that was signed by first signer @@ -141,7 +141,7 @@ public static void main(String args[]) throws Throwable { //Expect AccessControlException for setFactory permission System.out.println("Test Case 3"); cmd = constructCMD("both.jar", POLICY2, "false", "true"); - ProcessTools.executeTestJvm(cmd).shouldHaveExitValue(0); + ProcessTools.executeTestJava(cmd).shouldHaveExitValue(0); } diff --git a/test/jdk/java/security/Provider/SecurityProviderModularTest.java b/test/jdk/java/security/Provider/SecurityProviderModularTest.java index c475d593370..5bcf9a73301 100644 --- a/test/jdk/java/security/Provider/SecurityProviderModularTest.java +++ b/test/jdk/java/security/Provider/SecurityProviderModularTest.java @@ -255,7 +255,7 @@ private void execute(String args, String msgKey) throws Exception { } return !s.isEmpty(); }).toArray(String[]::new); - String out = ProcessTools.executeTestJvm(safeArgs).getOutput(); + String out = ProcessTools.executeTestJava(safeArgs).getOutput(); // Handle response. if ((msgKey != null && out.contains(MSG_MAP.get(msgKey)))) { System.out.printf("PASS: Expected Result: %s.%n", diff --git a/test/jdk/java/security/Security/signedfirst/DynStatic.java b/test/jdk/java/security/Security/signedfirst/DynStatic.java index 5256564064b..59e30de5462 100644 --- a/test/jdk/java/security/Security/signedfirst/DynStatic.java +++ b/test/jdk/java/security/Security/signedfirst/DynStatic.java @@ -78,7 +78,7 @@ public static void main(String[] args) throws Exception { CompilerUtils.compile(DYN_SRC, TEST_CLASSES, "-classpath", "exp.jar"); // Run the DynSignedProvFirst test program - ProcessTools.executeTestJvm("-classpath", + ProcessTools.executeTestJava("-classpath", TEST_CLASSES.toString() + File.pathSeparator + "exp.jar", "DynSignedProvFirst") .shouldContain("test passed"); @@ -87,7 +87,7 @@ public static void main(String[] args) throws Exception { CompilerUtils.compile(STATIC_SRC, TEST_CLASSES, "-classpath", "exp.jar"); // Run the StaticSignedProvFirst test program - ProcessTools.executeTestJvm("-classpath", + ProcessTools.executeTestJava("-classpath", TEST_CLASSES.toString() + File.pathSeparator + "exp.jar", "-Djava.security.properties=file:" + STATIC_PROPS, "StaticSignedProvFirst") diff --git a/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java b/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java index 69fe8effe70..83c2d85f6e4 100644 --- a/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java +++ b/test/jdk/java/security/SignedJar/spi-calendar-provider/TestSPISigned.java @@ -100,7 +100,7 @@ public static void main(String[] args) throws Throwable { testRun.add(classPath); testRun.add(TestSPISigned.class.getSimpleName()); testRun.add("run-test"); - OutputAnalyzer out = ProcessTools.executeTestJvm(testRun); + OutputAnalyzer out = ProcessTools.executeTestJava(testRun); out.shouldHaveExitValue(0); out.shouldContain("DEBUG: Getting xx language"); } diff --git a/test/jdk/java/security/cert/X509CertSelectorTest.java b/test/jdk/java/security/cert/X509CertSelectorTest.java index 0f77155dc3e..6b7cd560e8a 100644 --- a/test/jdk/java/security/cert/X509CertSelectorTest.java +++ b/test/jdk/java/security/cert/X509CertSelectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,10 +60,11 @@ import sun.security.x509.PrivateKeyUsageExtension; import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.X500Name; +import sun.security.util.Debug; /* * @test - * @bug 8074931 + * @bug 8074931 8296787 * @summary This class tests the X509CertSelector. The tests check particular criteria * by setting them to a value that should match our test certificate and * ensuring that they do match, then setting them to a value that should not @@ -191,6 +192,14 @@ private void testSerialNumber() { // good match selector.setSerialNumber(cert.getSerialNumber()); checkMatch(selector, cert, true); + + // check serial number format + String serialNum = Debug.toString(selector.getSerialNumber()); + String expected = "38:df:82:b8"; + if (!serialNum.equals(expected)) { + throw new RuntimeException("Serial number toString format is incorrect. Got: " + + serialNum + " Expected: " + expected); + } } // Tests matching on the issuer name contained in the certificate. diff --git a/test/jdk/java/sql/testng/test/sql/TimestampTests.java b/test/jdk/java/sql/testng/test/sql/TimestampTests.java index 7766b5a2b4c..fefe3276d47 100644 --- a/test/jdk/java/sql/testng/test/sql/TimestampTests.java +++ b/test/jdk/java/sql/testng/test/sql/TimestampTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -642,6 +642,31 @@ public void test52(long value, String ts) { assertEquals(ts1.toString(), ts, "ts1.toString() != ts"); } + @Test + public void test53() { + // The latest Instant that can be converted to a Timestamp. + Instant instant1 = Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 999_999_999); + assertEquals(Timestamp.from(instant1).toInstant(), instant1); + + // One nanosecond more, and converting it gets an overflow. + Instant instant2 = instant1.plusNanos(1); + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(instant2)); + + // The earliest Instant that can be converted to a Timestamp. + Instant instant3 = Instant.ofEpochSecond(Long.MIN_VALUE / 1000, 0); + assertEquals(Timestamp.from(instant3).toInstant(), instant3); + + // One nanosecond less, and converting it gets an overflow. + Instant instant4 = instant3.minusNanos(1); + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(instant4)); + + // The latest possible Instant will certainly overflow. + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MAX)); + + // The earliest possible Instant will certainly overflow. + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the diff --git a/test/jdk/java/time/test/java/time/format/TestUTCParse.java b/test/jdk/java/time/test/java/time/format/TestUTCParse.java index 6da94f04f04..c1766b47030 100644 --- a/test/jdk/java/time/test/java/time/format/TestUTCParse.java +++ b/test/jdk/java/time/test/java/time/format/TestUTCParse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test * @modules jdk.localedata - * @bug 8303440 8317979 + * @bug 8303440 8317979 8322647 * @summary Test parsing "UTC-XX:XX" text works correctly */ package test.java.time.format; @@ -43,8 +43,8 @@ public class TestUTCParse { static { - // Assuming CLDR's SHORT name for "America/Juneau" - // produces "UTC\u212209:00" + // Assuming CLDR's SHORT name for "America/Manaus" + // produces "UTC\u221204:00" System.setProperty("java.locale.providers", "CLDR"); } @@ -60,9 +60,9 @@ public Object[][] utcZoneIdStrings() { @Test public void testUTCShortNameRoundTrip() { var fmt = DateTimeFormatter.ofPattern("z", Locale.FRANCE); - var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Juneau")); + var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Manaus")); var formatted = fmt.format(zdt); - assertEquals(formatted, "UTC\u221209:00"); + assertEquals(formatted, "UTC\u221204:00"); assertEquals(fmt.parse(formatted).query(TemporalQueries.zoneId()), zdt.getZone()); } diff --git a/test/jdk/java/util/Currency/PropertiesTestRun.java b/test/jdk/java/util/Currency/PropertiesTestRun.java index 6f2ea28a90d..baec22f3e86 100644 --- a/test/jdk/java/util/Currency/PropertiesTestRun.java +++ b/test/jdk/java/util/Currency/PropertiesTestRun.java @@ -116,7 +116,7 @@ private static Stream PropertiesTestMethods() { // Launch a PropertiesTest method using the TEST JDK private static void executeTestJDKMethod(String... params) throws Throwable { - int exitStatus = ProcessTools.executeTestJvm(params).getExitValue(); + int exitStatus = ProcessTools.executeTestJava(params).getExitValue(); if (exitStatus != 0) { fail("Process started with: " + Arrays.toString(params) + " failed"); } @@ -126,7 +126,7 @@ private static void executeTestJDKMethod(String... params) throws Throwable { private static void executeWritableJDKMethod(String... params) throws Throwable { // Need to include WritableJDK javapath, TEST JDK classpath String[] allParams = new String[3+params.length+Utils.getTestJavaOpts().length]; - // We don't use executeTestJvm() because we want to point to separate JDK java path + // We don't use executeTestJava() because we want to point to separate JDK java path allParams[0] = WRITABLE_JDK_JAVA_PATH; allParams[1] = "-cp"; allParams[2] = System.getProperty("java.class.path"); diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index c4fdc5ca2e0..53788c899b3 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -25,7 +25,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 8283277 8296239 + * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -86,7 +86,7 @@ public class ValidateISO4217 { // Codes that are obsolete, do not have related country, extra currency private static final String otherCodes = "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" - + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-HRK-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" + "YUM-ZMK-ZWD-ZWN-ZWR"; @@ -168,7 +168,7 @@ private static void processColumns(StringTokenizer tokens, String country) throw if (format == null) { createDateFormat(); } - // If the cut-over already passed, test the changed data too + // If the cut-over already passed, use the new curency for ISO4217Codes if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) { currency = tokens.nextToken(); numeric = tokens.nextToken(); @@ -267,20 +267,21 @@ private static List additionalCodesProvider() { * throws an IllegalArgumentException or returns null. The test data * supplied is every possible combination of AA -> ZZ. */ - @ParameterizedTest - @MethodSource("codeCombos") - public void twoLetterCodesTest(String country) { - if (codes[toIndex(country)] == UNDEFINED) { - // if a code is undefined / 0, creating a Currency from it - // should throw an IllegalArgumentException - assertThrows(IllegalArgumentException.class, - ()-> Currency.getInstance(Locale.of("", country)), - "Error: This should be an undefined code and throw IllegalArgumentException: " + country); - } else if (codes[toIndex(country)] == SKIPPED) { - // if a code is marked as skipped / 2, creating a Currency from it - // should return null - assertNull(Currency.getInstance(Locale.of("", country)), - "Error: Currency.getInstance() for this locale should return null: " + country); + @Test + public void twoLetterCodesTest() { + for (String country : codeCombos()) { + if (codes[toIndex(country)] == UNDEFINED) { + // if a code is undefined / 0, creating a Currency from it + // should throw an IllegalArgumentException + assertThrows(IllegalArgumentException.class, + () -> Currency.getInstance(Locale.of("", country)), + "Error: This should be an undefined code and throw IllegalArgumentException: " + country); + } else if (codes[toIndex(country)] == SKIPPED) { + // if a code is marked as skipped / 2, creating a Currency from it + // should return null + assertNull(Currency.getInstance(Locale.of("", country)), + "Error: Currency.getInstance() for this locale should return null: " + country); + } } } diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index 4e33a62c05e..6e85de5e6d2 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 175 -# (As of 31 March 2023) +# Amendments up until ISO 4217 AMENDMENT NUMBER 176 +# (As of 06 December 2023) # # Version FILEVERSION=3 -DATAVERSION=175 +DATAVERSION=176 # ISO 4217 currency data AF AFN 971 2 @@ -67,9 +67,9 @@ CD CDF 976 2 CK NZD 554 2 CR CRC 188 2 CI XOF 952 0 -HR HRK 191 2 2022-12-31-23-00-00 EUR 978 2 +HR EUR 978 2 CU CUP 192 2 -CW ANG 532 2 +CW ANG 532 2 2025-04-01-04-00-00 XCG 532 2 CY EUR 978 2 CZ CZK 203 2 DK DKK 208 2 @@ -233,7 +233,7 @@ LK LKR 144 2 SD SDG 938 2 SR SRD 968 2 SJ NOK 578 2 -SX ANG 532 2 +SX ANG 532 2 2025-04-01-04-00-00 XCG 532 2 SZ SZL 748 2 SE SEK 752 2 CH CHF 756 2 diff --git a/test/jdk/java/util/Locale/UseOldISOCodesTest.java b/test/jdk/java/util/Locale/UseOldISOCodesTest.java index b38537bceca..01f997a743d 100644 --- a/test/jdk/java/util/Locale/UseOldISOCodesTest.java +++ b/test/jdk/java/util/Locale/UseOldISOCodesTest.java @@ -41,7 +41,7 @@ public class UseOldISOCodesTest { // Ensure java.locale.useOldISOCodes is only interpreted at runtime startup @Test public void staticInitializationTest() throws Exception { - ProcessTools.executeTestJvm("-Djava.locale.useOldISOCodes=true", "UseOldISOCodesTest$Runner") + ProcessTools.executeTestJava("-Djava.locale.useOldISOCodes=true", "UseOldISOCodesTest$Runner") .outputTo(System.out) .errorTo(System.err) .shouldHaveExitValue(0); diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index c5483b48512..f92096d49aa 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2023c +tzdata2023d diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt index 07c5edbafee..82bad17c553 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt @@ -148,7 +148,6 @@ Link America/Puerto_Rico America/Tortola Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java b/test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java index f8bb222fb98..5a78d2791fe 100644 --- a/test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java +++ b/test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,8 @@ * @test * @bug 8066859 * @summary Check that AQS-based locks, conditions, and CountDownLatches do not fail when encountering OOME - * @run main/othervm -XX:-UseGCOverheadLimit -Xmx48M -XX:-UseTLAB OOMEInAQS + * @requires vm.gc.G1 + * @run main/othervm -XX:+UseG1GC -XX:-UseGCOverheadLimit -Xmx48M -XX:-UseTLAB OOMEInAQS */ public class OOMEInAQS extends Thread { diff --git a/test/jdk/java/util/prefs/CheckUserPrefsStorage.java b/test/jdk/java/util/prefs/CheckUserPrefsStorage.java index 51ecae932d1..1f772f4811a 100644 --- a/test/jdk/java/util/prefs/CheckUserPrefsStorage.java +++ b/test/jdk/java/util/prefs/CheckUserPrefsStorage.java @@ -42,7 +42,7 @@ public static void main(String[] args) throws Throwable { } public static void run(String testName) throws Exception { - ProcessTools.executeTestJvm("-Djava.util.prefs.userRoot=.", testName) + ProcessTools.executeTestJava("-Djava.util.prefs.userRoot=.", testName) .outputTo(System.out) .errorTo(System.out) .shouldHaveExitValue(0); diff --git a/test/jdk/java/util/zip/CopyZipFile.java b/test/jdk/java/util/zip/CopyZipFile.java index e6fa4bfe057..ae90e4b6400 100644 --- a/test/jdk/java/util/zip/CopyZipFile.java +++ b/test/jdk/java/util/zip/CopyZipFile.java @@ -23,99 +23,120 @@ /** * @test + * @bug 8253952 * @summary Test behaviour when copying ZipEntries between zip files. - * @run main/othervm CopyZipFile + * @run junit CopyZipFile */ -import java.io.File; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Enumeration; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.zip.CRC32; -import java.util.zip.Deflater; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; +import java.util.zip.*; + +import static org.junit.jupiter.api.Assertions.*; public class CopyZipFile { - private static final String ZIP_FILE = "first.zip"; - private static final String TEST_STRING = "TestTestTest"; + // ZIP file created in this test + private Path zip = Path.of("first.zip"); + // The content to put in each entry + private static final byte[] TEST_STRING = "TestTestTest".getBytes(StandardCharsets.UTF_8); - private static void createZip(String zipFile) throws Exception { - File f = new File(zipFile); - f.deleteOnExit(); - try (OutputStream os = new FileOutputStream(f); + /** + * Create the sample ZIP file used in this test, including a STORED entry + * and DEFLATE entries with various compression levels. + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void createZip() throws IOException { + // By default, ZipOutputStream creates zip files with Local File Headers + // without size, compressed size and crc values and an extra Data + // Descriptor (see https://en.wikipedia.org/wiki/Zip_(file_format) + // after the data belonging to that entry with these values if in the + // corresponding ZipEntry one of the size, compressedSize or crc fields is + // equal to '-1' (which is the default for newly created ZipEntries). + try (OutputStream os = Files.newOutputStream(zip) ; ZipOutputStream zos = new ZipOutputStream(os)) { // First file will be compressed with DEFAULT_COMPRESSION (i.e. -1 or 6) - zos.putNextEntry(new ZipEntry("test1.txt")); - zos.write(TEST_STRING.getBytes()); - zos.closeEntry(); + zos.setLevel(Deflater.DEFAULT_COMPRESSION); + zos.putNextEntry(new ZipEntry("DEFAULT_COMPRESSION.txt")); + zos.write(TEST_STRING); + // Second file won't be compressed at all (i.e. STORED) zos.setMethod(ZipOutputStream.STORED); - ZipEntry ze = new ZipEntry("test2.txt"); - int length = TEST_STRING.length(); - ze.setSize(length); - ze.setCompressedSize(length); + ZipEntry ze = new ZipEntry("STORED.txt"); + ze.setSize(TEST_STRING.length); + ze.setCompressedSize(TEST_STRING.length); CRC32 crc = new CRC32(); - crc.update(TEST_STRING.getBytes("utf8"), 0, length); + crc.update(TEST_STRING); ze.setCrc(crc.getValue()); zos.putNextEntry(ze); - zos.write(TEST_STRING.getBytes()); + zos.write(TEST_STRING); + // Third file will be compressed with NO_COMPRESSION (i.e. 0) zos.setMethod(ZipOutputStream.DEFLATED); zos.setLevel(Deflater.NO_COMPRESSION); - zos.putNextEntry(new ZipEntry("test3.txt")); - zos.write(TEST_STRING.getBytes()); + zos.putNextEntry(new ZipEntry("NO_COMPRESSION.txt")); + zos.write(TEST_STRING); + // Fourth file will be compressed with BEST_SPEED (i.e. 1) zos.setLevel(Deflater.BEST_SPEED); - zos.putNextEntry(new ZipEntry("test4.txt")); - zos.write(TEST_STRING.getBytes()); + zos.putNextEntry(new ZipEntry("BEST_SPEED.txt")); + zos.write(TEST_STRING); + // Fifth file will be compressed with BEST_COMPRESSION (i.e. 9) zos.setLevel(Deflater.BEST_COMPRESSION); - zos.putNextEntry(new ZipEntry("test5.txt")); - zos.write(TEST_STRING.getBytes()); + zos.putNextEntry(new ZipEntry("BEST_COMPRESSION.txt")); + zos.write(TEST_STRING); } } - public static void main(String args[]) throws Exception { - // By default, ZipOutputStream creates zip files with Local File Headers - // without size, compressedSize and crc values and an extra Data - // Descriptor (see https://en.wikipedia.org/wiki/Zip_(file_format) - // after the data belonging to that entry with these values if in the - // corresponding ZipEntry one of the size, compressedSize or crc fields is - // equal to '-1' (which is the default for newly created ZipEntries). - createZip(ZIP_FILE); - - // Now read all the entries of the newly generated zip file with a ZipInputStream - // and copy them to a new zip file with the help of a ZipOutputStream. - // This only works reliably because the generated zip file has no values for the - // size, compressedSize and crc values of a zip entry in the local file header and - // therefore the ZipEntry objects created by ZipOutputStream.getNextEntry() will have - // all these fields set to '-1'. - ZipEntry entry; - byte[] buf = new byte[512]; - try (InputStream is = new FileInputStream(ZIP_FILE); - ZipInputStream zis = new ZipInputStream(is); - OutputStream os = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(os)) { - while((entry = zis.getNextEntry())!=null) { + /** + * Delete the ZIP file produced by this test + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Read all entries using ZipInputStream.getNextEntry and copy them + * to a new zip file using ZipOutputStream.putNextEntry. This only works + * reliably because the input zip file has no values for the size, compressedSize + * and crc values of streamed zip entries in the local file header and + * therefore the ZipEntry objects created by ZipOutputStream.getNextEntry + * will have all these fields set to '-1'. + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void copyFromZipInputStreamToZipOutputStream() throws IOException { + + try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zip)); + ZipOutputStream zos = new ZipOutputStream(OutputStream.nullOutputStream())) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { // ZipInputStream.getNextEntry() only reads the Local File Header of a zip entry, // so for the zip file we've just generated the ZipEntry fields 'size', 'compressedSize` // and 'crc' for deflated entries should be uninitialized (i.e. '-1'). System.out.println( - String.format("name=%s, clen=%d, len=%d, crc=%d", - entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc())); - if (entry.getMethod() == ZipEntry.DEFLATED && - (entry.getCompressedSize() != -1 || entry.getSize() != -1 || entry.getCrc() != -1)) { - throw new Exception("'size', 'compressedSize' and 'crc' shouldn't be initialized at this point."); + String.format("name=%s, clen=%d, len=%d, crc=%d", + entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc())); + if (entry.getMethod() == ZipEntry.DEFLATED) { + // Expect size, compressed size and crc to not be initialized at this point + assertEquals(-1, entry.getCompressedSize()); + assertEquals(-1, entry.getSize()); + assertEquals(-1, entry.getCrc()); } zos.putNextEntry(entry); zis.transferTo(zos); @@ -124,29 +145,37 @@ public static void main(String args[]) throws Exception { // Descriptor (if any) after the data and will have updated the 'size', 'compressedSize' and 'crc' // fields of the ZipEntry object. System.out.println( - String.format("name=%s, clen=%d, len=%d, crc=%d\n", - entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc())); - if (entry.getCompressedSize() == -1 || entry.getSize() == -1) { - throw new Exception("'size' and 'compressedSize' must be initialized at this point."); - } + String.format("name=%s, clen=%d, len=%d, crc=%d\n", + entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc())); + // Expect size, compressed size and crc to be initialized at this point + assertNotEquals(-1, entry.getCompressedSize()); + assertNotEquals(-1, entry.getSize()); + assertNotEquals(-1, entry.getCrc()); } } + } - // Now we read all the entries of the initially generated zip file with the help - // of the ZipFile class. The ZipFile class reads all the zip entries from the Central - // Directory which must have accurate information for size, compressedSize and crc. - // This means that all ZipEntry objects returned from ZipFile will have correct - // settings for these fields. - // If the compression level was different in the initial zip file (which we can't find - // out any more now because the zip file format doesn't record this information) the - // size of the re-compressed entry we are writing to the ZipOutputStream might differ - // from the original compressed size recorded in the ZipEntry. This would result in an - // "invalid entry compressed size" ZipException if ZipOutputStream wouldn't ignore - // the implicitely set compressed size attribute of ZipEntries read from a ZipFile - // or ZipInputStream. - try (OutputStream os = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(os); - ZipFile zf = new ZipFile(ZIP_FILE)) { + /** + * Read all entries using the ZipFile class and copy them to a new zip file + * using ZipOutputStream.putNextEntry. + * The ZipFile class reads all the zip entries from the Central + * Directory, which has accurate information for size, compressedSize and crc. + * This means that all ZipEntry objects returned from ZipFile will have correct + * settings for these fields. + * If the compression level was different in the input zip file (which we can't know + * because the zip file format doesn't record this information), the + * size of the re-compressed entry we are writing to the ZipOutputStream might differ + * from the original compressed size recorded in the ZipEntry. This would result in an + * "invalid entry compressed size" ZipException if ZipOutputStream wouldn't ignore + * the implicitely set compressed size attribute of ZipEntries read from a ZipFile + * or ZipInputStream. + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void copyFromZipFileToZipOutputStream() throws IOException { + try (ZipOutputStream zos = new ZipOutputStream(OutputStream.nullOutputStream()); + ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry entry; Enumeration entries = zf.entries(); while (entries.hasMoreElements()) { entry = entries.nextElement(); @@ -154,48 +183,84 @@ public static void main(String args[]) throws Exception { String.format("name=%s, clen=%d, len=%d, crc=%d\n", entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc())); - if (entry.getCompressedSize() == -1 || entry.getSize() == -1) { - throw new Exception("'size' and 'compressedSize' must be initialized at this point."); - } - InputStream is = zf.getInputStream(entry); + // Expect size, compressed size and crc to be initialized at this point + assertNotEquals(-1, entry.getCompressedSize()); + assertNotEquals(-1, entry.getSize()); + assertNotEquals(-1, entry.getCrc()); + zos.putNextEntry(entry); - is.transferTo(zos); + try (InputStream is = zf.getInputStream(entry)) { + is.transferTo(zos); + } zos.closeEntry(); } } + } + + /** + * If the compressed size is set explicitly using ZipEntry.setCompressedSize(), + * then the entry will be restreamed with a data descriptor and the compressed size + * recomputed. If the source compression level was different from the target compression + * level, the compressed sizes may differ and a ZipException will be thrown + * when the entry is closed in ZipOutputStream.closeEntry + * + * @throws IOException if an unexpected IOException is thrown + */ + @Test + public void explicitCompressedSizeWithDifferentCompressionLevels() throws IOException { + try (ZipOutputStream zos = new ZipOutputStream(OutputStream.nullOutputStream()); + ZipFile zf = new ZipFile(zip.toFile())) { + // Be explicit about the default compression level + zos.setLevel(Deflater.DEFAULT_COMPRESSION); - // The compressed size attribute of a ZipEntry shouldn't be ignored if it was set - // explicitely by calling ZipEntry.setCpompressedSize() - try (OutputStream os = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(os); - ZipFile zf = new ZipFile(ZIP_FILE)) { Enumeration entries = zf.entries(); while (entries.hasMoreElements()) { - try { - entry = entries.nextElement(); - entry.setCompressedSize(entry.getCompressedSize()); - InputStream is = zf.getInputStream(entry); + ZipEntry entry = entries.nextElement(); + + // Explicitly setting the compressed size will disable data descriptors + // and enable validation that the compressed size in the ZipEntry matches the + // actual compressed size written by ZipOutputStream + entry.setCompressedSize(entry.getCompressedSize()); + + try (InputStream is = zf.getInputStream(entry)) { zos.putNextEntry(entry); is.transferTo(zos); - zos.closeEntry(); - if ("test3.txt".equals(entry.getName())) { - throw new Exception( - "Should throw a ZipException if ZipEntry.setCpompressedSize() was called."); - } - } catch (ZipException ze) { - if ("test1.txt".equals(entry.getName()) || "test2.txt".equals(entry.getName())) { - throw new Exception( - "Shouldn't throw a ZipExcpetion for STORED files or files compressed with DEFAULT_COMPRESSION"); + // Some compression levels lead to unexpected recompressed sizes when closing the entry + switch (entry.getName()) { + case "DEFAULT_COMPRESSION.txt" -> { + // DEFAULT_COMPRESSION matches expected size + zos.closeEntry(); + } + case "STORED.txt" -> { + // STORED should not throw + zos.closeEntry(); + } + case "NO_COMPRESSION.txt", "BEST_SPEED.txt" -> { + // NO_COMPRESSION and BEST_SPEED should lead to an unexpected recompressed size + ZipException ze = assertThrows(ZipException.class, () -> { + zos.closeEntry(); + }); + + // Hack to fix and close the offending zip entry with the correct recompressed size. + // The exception message is something like: + // "invalid entry compressed size (expected 12 but got 7 bytes)" + // and we need to extract the second integer. + Pattern cSize = Pattern.compile("\\d+"); + Matcher m = cSize.matcher(ze.getMessage()); + m.find(); + m.find(); + entry.setCompressedSize(Integer.parseInt(m.group())); + zos.closeEntry(); + } + case "BEST_COMPRESSION.txt" -> { + // BEST_COMPRESSION produces the same compressed + // size as DEFAULT_COMPRESSION for sample content + zos.closeEntry(); + } + default -> { + throw new IllegalArgumentException("Unexpected entry " + entry.getName()); + } } - // Hack to fix and close the offending zip entry with the correct compressed size. - // The exception message is something like: - // "invalid entry compressed size (expected 12 but got 7 bytes)" - // and we need to extract the second integer. - Pattern cSize = Pattern.compile("\\d+"); - Matcher m = cSize.matcher(ze.getMessage()); - m.find(); - m.find(); - entry.setCompressedSize(Integer.parseInt(m.group())); } } } diff --git a/test/jdk/java/util/zip/EntryCount64k.java b/test/jdk/java/util/zip/EntryCount64k.java index 08d896a124a..2dac7643de2 100644 --- a/test/jdk/java/util/zip/EntryCount64k.java +++ b/test/jdk/java/util/zip/EntryCount64k.java @@ -160,7 +160,7 @@ static void checkCanRead(File zipFile, int entryCount) throws Throwable { } // Check java -jar - OutputAnalyzer a = ProcessTools.executeTestJvm("-jar", zipFile.getName()); + OutputAnalyzer a = ProcessTools.executeTestJava("-jar", zipFile.getName()); a.shouldHaveExitValue(0); a.stdoutShouldMatch("\\AMain\\Z"); a.stderrShouldMatch("\\A\\Z"); diff --git a/test/jdk/java/util/zip/ZipCoding.java b/test/jdk/java/util/zip/ZipCoding.java index 852522b9a6a..14a0e96f174 100644 --- a/test/jdk/java/util/zip/ZipCoding.java +++ b/test/jdk/java/util/zip/ZipCoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,111 +23,185 @@ /** * @test - * @bug 4244499 4532049 4700978 4820807 4980042 + * @bug 4244499 4532049 4700978 4820807 4980042 7009069 8322802 * @summary Test ZipInputStream, ZipOutputStream and ZipFile with non-UTF8 encoding * @modules jdk.charsets + * @run junit ZipCoding */ +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import java.io.*; import java.nio.charset.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; +import java.util.stream.Stream; import java.util.zip.*; +import static org.junit.jupiter.api.Assertions.*; + public class ZipCoding { - public static void main(String[] args) throws Exception { + // The data to write to ZIP entries in this test + private static byte[] ENTRY_DATA = "German Umlaut \u00fc in entry data" + .getBytes(StandardCharsets.ISO_8859_1); + + /** + * Provide arguments used for parameterized tests + * @return a stream of argument lists + */ + public static Stream charsetsAndNames() { + // Arguments are: Write charset, read charset, entry name, comment + return Stream.of( + // MS code page 932 for the Japanese language + Arguments.of("MS932", "MS932", + "\u4e00\u4e01", + "\uff67\uff68\uff69\uff6a\uff6b\uff6c"), - test("MS932", - "\u4e00\u4e01", "\uff67\uff68\uff69\uff6a\uff6b\uff6c"); + // Code page for the IBM PC + Arguments.of("ibm437", "ibm437", + "\u00e4\u00fc", + "German Umlaut \u00fc in comment"), - test("ibm437", - "\u00e4\u00fc", "German Umlaut \u00fc in comment"); + // UTF-8 with Japanese characters + Arguments.of("utf-8", "utf-8", + "\u4e00\u4e01", + "\uff67\uff68\uff69\uff6a\uff6b\uff6c"), - test("utf-8", - "\u4e00\u4e01", "\uff67\uff68\uff69\uff6a\uff6b\uff6c"); + // UTF-8 with characters in the Latin1 range + Arguments.of("utf-8", "utf-8", + "\u00e4\u00fc", + "German Umlaut \u00fc in comment"), - test("utf-8", - "\u00e4\u00fc", "German Umlaut \u00fc in comment"); + // UTF-8 with surrogate pairs + Arguments.of("utf-8", "utf-8", + "Surrogate\ud801\udc01", + "Surrogates \ud800\udc00 in comment"), - test("utf-8", - "Surrogate\ud801\udc01", "Surrogates \ud800\udc00 in comment"); + // ZipOutputStream sets the 'Language encoding flag' when writing using UTF-8 + // UTF-8 should be used for decoding, regardless of the opening charset + // UTF-8 with Japanese characters, opened with MS932 + Arguments.of("utf-8", "MS932", + "\u4e00\u4e01", + "\uff67\uff68\uff69\uff6a\uff6b\uff6c"), + + // UTF-8 with characters in latin1 range, opened with iso-8859-1 + Arguments.of("utf-8", "iso-8859-1", + "\u00e4\u00fc", + "German Umlaut \u00fc in comment"), + // UTF-8 with surrogate pairs, opened with MS932 + Arguments.of("utf-8", "MS932", + "Surrogate\ud801\udc01", + "Surrogates \ud800\udc00 in comment") + ); } - static void testZipInputStream(InputStream is, Charset cs, - String name, String comment, byte[] bb) - throws Exception - { - try (ZipInputStream zis = new ZipInputStream(is, cs)) { + /** + * Verify that ZipInputStream decodes entry names and comments + * using the charset provided to its constructor, or that it decodes + * using UTF-8 when the 'Language encoding flag' is set + * + * @param writeCharset the charset to use for ZipOutputStream when producing the ZIP + * @param readCharset the charset to use when opening the ZipInputStream + * @param name the entry name + * @param comment the entry comment (not read by ZipInputStream) + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("charsetsAndNames") + public void testZipInputStream(String writeCharset, + String readCharset, + String name, + String comment) throws IOException { + + byte[] zip = createZIP(writeCharset, name, comment); + + try (InputStream in = new ByteArrayInputStream(zip); + ZipInputStream zis = new ZipInputStream(in, Charset.forName(readCharset))) { ZipEntry e = zis.getNextEntry(); - if (e == null || ! name.equals(e.getName())) - throw new RuntimeException("ZipIS name doesn't match!"); - byte[] bBuf = new byte[bb.length << 1]; - int n = zis.read(bBuf, 0, bBuf.length); - if (n != bb.length || - !Arrays.equals(bb, Arrays.copyOf(bBuf, n))) { - throw new RuntimeException("ZipIS content doesn't match!"); - } + assertNotNull(e); + assertEquals(name, e.getName(), + "ZipInputStream.getNextEntry() returned unexpected entry name"); + assertNull(e.getComment()); // No comment in the LOC header + assertArrayEquals(ENTRY_DATA, zis.readAllBytes(), "Unexpected ZIP entry data"); } } - static void testZipFile(File f, Charset cs, - String name, String comment, byte[] bb) - throws Exception - { - try (ZipFile zf = new ZipFile(f, cs)) { + /** + * Verify that ZipFile decodes entry names and comments + * using the charset provided to its constructor, or that it decodes + * using UTF-8 when the 'Language encoding flag' is set + * + * @param writeCharset the charset to use for ZipOutputStream when producing the ZIP + * @param readCharset the charset to use when opening the ZipFile + * @param name the name of the entry + * @param comment the comment of the entry + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("charsetsAndNames") + public void testZipFile(String writeCharset, + String readCharset, + String name, + String comment) throws IOException { + + byte[] zip = createZIP(writeCharset, name, comment); + + Path f = Path.of("zfcoding.zip"); + Files.write(f, zip); + + try (ZipFile zf = new ZipFile(f.toFile(), Charset.forName(readCharset))) { + // Test using ZipFile.entries Enumeration zes = zf.entries(); ZipEntry e = (ZipEntry)zes.nextElement(); - if (! name.equals(e.getName()) || - ! comment.equals(e.getComment())) - throw new RuntimeException("ZipFile: name/comment doesn't match!"); - InputStream is = zf.getInputStream(e); - if (is == null) - throw new RuntimeException("ZipFile: getIS failed!"); - byte[] bBuf = new byte[bb.length << 1]; - int n = 0; - int nn =0; - while ((nn = is.read(bBuf, n, bBuf.length-n)) != -1) { - n += nn; - } - if (n != bb.length || - !Arrays.equals(bb, Arrays.copyOf(bBuf, n))) { - throw new RuntimeException("ZipFile content doesn't match!"); + assertNotNull(e); + assertEquals(name, e.getName(), "ZipFile.entries() returned unexpected entry name"); + assertEquals(comment, e.getComment(), "ZipFile.entries() returned unexpected entry comment"); + + // Test using ZipFile.getEntry + e = zf.getEntry(name); + assertNotNull(e, + String.format("Entry lookup failed on ZIP encoded with %s and opened with %s", + writeCharset, readCharset)); + assertEquals(name, e.getName(), "ZipFile.getEntry() returned unexpected entry name"); + assertEquals(comment, e.getComment(), "ZipFile.getEntry() returned unexpected entry comment"); + try (InputStream is = zf.getInputStream(e)) { + assertNotNull(is); + assertArrayEquals(ENTRY_DATA, is.readAllBytes(), "Unexpected ZIP entry data"); } } + + Files.deleteIfExists(f); } - static void test(String csn, String name, String comment) - throws Exception - { - byte[] bb = "This is the content of the zipfile".getBytes("ISO-8859-1"); - Charset cs = Charset.forName(csn); + /** + * Create a ZIP file containing an entry with the given name + * and comment, encoded using the given charset. + * Note that if the charset is UTF-8, ZipOutputStream will + * set the 'Language encoding flag' for the entry. + * + * @param charset the charset passed to the ZipOutputStream constructor + * @param name the name of the entry to add + * @param comment the comment of the entry to add + * @return a byte array containing the ZIP file + * + * @throws IOException if an unexpected IOException occurs + */ + private byte[] createZIP(String charset, String name, String comment) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ZipOutputStream zos = new ZipOutputStream(baos, cs)) { + try (ZipOutputStream zos = new ZipOutputStream(baos, Charset.forName(charset))) { ZipEntry e = new ZipEntry(name); e.setComment(comment); zos.putNextEntry(e); - zos.write(bb, 0, bb.length); + zos.write(ENTRY_DATA); zos.closeEntry(); } - ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray()); - testZipInputStream(bis, cs, name, comment, bb); - - if ("utf-8".equals(csn)) { - // USE_UTF8 should be set - bis.reset(); - testZipInputStream(bis, Charset.forName("MS932"), name, comment, bb); - } - - File f = new File(new File(System.getProperty("test.dir", ".")), - "zfcoding.zip"); - try (FileOutputStream fos = new FileOutputStream(f)) { - baos.writeTo(fos); - } - testZipFile(f, cs, name, comment, bb); - if ("utf-8".equals(csn)) { - testZipFile(f, Charset.forName("MS932"), name, comment, bb); - } - f.delete(); + return baos.toByteArray(); } } diff --git a/test/jdk/java/util/zip/ZipFile/CopyJar.java b/test/jdk/java/util/zip/ZipFile/CopyJar.java deleted file mode 100644 index abeb1f3c462..00000000000 --- a/test/jdk/java/util/zip/ZipFile/CopyJar.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. - * 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 1.1 99/06/01 - @bug 4239446 - @summary Make sure the ZipEntry fields are correct. - */ - -import java.io.*; -import java.util.zip.*; - -public class CopyJar { - public static void main(String args[]) throws Exception { - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), - "input.jar"))) { - ZipEntry ze = zf.getEntry("ReleaseInflater.java"); - ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream()); - InputStream in = zf.getInputStream(ze); - byte[] b = new byte[128]; - int n; - zos.putNextEntry(ze); - while((n = in.read(b)) != -1) { - zos.write(b, 0, n); - } - zos.close(); - } - } -} diff --git a/test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java b/test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java index befdf4cac15..04a1157a2f8 100644 --- a/test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java +++ b/test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4770745 6218846 6218848 6237956 8313765 + * @bug 4770745 6218846 6218848 6237956 8313765 8316141 * @summary test for correct detection and reporting of corrupted zip files * @author Martin Buchholz * @run junit CorruptedZipFiles @@ -262,7 +262,7 @@ public void insufficientFilenameLength() throws IOException { public void excessiveExtraFieldLength() throws IOException { buffer.put(cenpos+CENEXT, (byte) 0xff); buffer.put(cenpos+CENEXT+1, (byte) 0xff); - assertZipException(".*extra data field size too long.*"); + assertZipException(".*bad header size.*"); } /* @@ -273,7 +273,7 @@ public void excessiveExtraFieldLength() throws IOException { @Test public void excessiveExtraFieldLength2() throws IOException { buffer.putShort(cenpos+CENEXT, (short) 0xfdfd); - assertZipException(".*extra data field size too long.*"); + assertZipException(".*bad header size.*"); } /* diff --git a/test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java b/test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java index e0a987f8bdc..cafc17accf8 100644 --- a/test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java +++ b/test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java @@ -42,7 +42,7 @@ public class DeleteTempJarTest { public static void main(String[] args) throws Exception { - String tmpFile = ProcessTools.executeTestJvm(DeleteTempJar.class.getName()) + String tmpFile = ProcessTools.executeTestJava(DeleteTempJar.class.getName()) .shouldHaveExitValue(0) .getStdout(); diff --git a/test/jdk/java/util/zip/ZipFile/EnumAfterClose.java b/test/jdk/java/util/zip/ZipFile/EnumAfterClose.java deleted file mode 100644 index 38c00466e8f..00000000000 --- a/test/jdk/java/util/zip/ZipFile/EnumAfterClose.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - * 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 4290060 - @summary Check if the zip file is closed before access any - elements in the Enumeration. - */ - -import java.io.*; -import java.util.zip.*; -import java.util.Enumeration; - -public class EnumAfterClose { - public static void main(String args[]) throws Exception { - Enumeration e; - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), - "input.zip"))) { - e = zf.entries(); - } - // ensure that the ZipFile is closed before checking the Enumeration - try { - if (e.hasMoreElements()) { - ZipEntry ze = (ZipEntry)e.nextElement(); - } - } catch (IllegalStateException ie) { - } - } -} diff --git a/test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java b/test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java new file mode 100644 index 00000000000..e165e5d2a0a --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4290060 + @summary Check if the zip file is closed before access any + elements in the Enumeration. + @run junit EnumerateAfterClose + */ + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class EnumerateAfterClose { + + // ZIP file used in this test + private Path zip = Path.of("enum-after-close.zip"); + + /** + * Create a sample ZIP file for use by this test + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + zo.putNextEntry(new ZipEntry("file.txt")); + zo.write("hello".getBytes(StandardCharsets.UTF_8)); + } + } + + /** + * Delete the ZIP file produced by this test + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Attempting to using a ZipEntry Enumeration after its backing + * ZipFile is closed should throw IllegalStateException. + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void enumeratingAfterCloseShouldThrowISE() throws IOException { + // Retain a reference to an enumeration backed by a closed ZipFile + Enumeration e; + try (ZipFile zf = new ZipFile(zip.toFile())) { + e = zf.entries(); + } + // Using the enumeration after the ZipFile is closed should throw ISE + assertThrows(IllegalStateException.class, () -> { + if (e.hasMoreElements()) { + ZipEntry ze = (ZipEntry)e.nextElement(); + } + }); + } +} diff --git a/test/jdk/java/util/zip/ZipFile/FinalizeInflater.java b/test/jdk/java/util/zip/ZipFile/FinalizeInflater.java index e80fd749076..254f1d445ea 100644 --- a/test/jdk/java/util/zip/ZipFile/FinalizeInflater.java +++ b/test/jdk/java/util/zip/ZipFile/FinalizeInflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,64 @@ /* @test @bug 7003462 @summary Make sure cached Inflater does not get finalized. + @run junit FinalizeInflater */ -import java.io.File; -import java.io.InputStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; public class FinalizeInflater { - public static void main(String[] args) throws Throwable { - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), "input.zip"))) - { - ZipEntry ze = zf.getEntry("ReadZip.java"); + // ZIP file produced by this test + private Path zip = Path.of("finalize-inflater.zip"); + + /** + * Create the sample ZIP used in this test + * + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + zo.putNextEntry(new ZipEntry("file.txt")); + byte[] hello = "hello".getBytes(StandardCharsets.UTF_8); + for (int i = 0; i < 100; i++) { + zo.write(hello); + } + } + } + + /** + * Delete the ZIP file produced by this test + * + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * A cached Inflater should not be made invalid by finalization + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void shouldNotFinalizeInflaterInPool() throws IOException { + try (ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry ze = zf.getEntry("file.txt"); read(zf.getInputStream(ze)); System.gc(); System.runFinalization(); @@ -51,15 +95,10 @@ private static void read(InputStream is) throws IOException { Wrapper wrapper = new Wrapper(is); - byte[] buffer = new byte[32]; - try { - while(is.read(buffer)>0){} - } catch (IOException ioe) { - ioe.printStackTrace(); - } + is.readAllBytes(); } - static class Wrapper{ + static class Wrapper { InputStream is; public Wrapper(InputStream is) { this.is = is; diff --git a/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java deleted file mode 100644 index 34882451751..00000000000 --- a/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. - * 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 4528128 6846616 - @summary Test if reading InputStream of a closed ZipFile crashes VM - @author kladko - */ - - -import java.util.zip.*; -import java.io.*; -import java.util.*; - -public class ReadAfterClose { - public static void main(String[] argv) throws Exception { - InputStream in; - try (ZipFile zf = new ZipFile( - new File(System.getProperty("test.src","."),"crash.jar"))) { - ZipEntry zent = zf.getEntry("Test.java"); - in = zf.getInputStream(zent); - } - // ensure zf is closed at this point - try { - in.read(); - } catch (IOException e) { - return; - } - throw new Exception("Test failed."); - } -} diff --git a/test/jdk/java/util/zip/ZipFile/ReadZip.java b/test/jdk/java/util/zip/ZipFile/ReadZip.java index 33db2552986..5aa9ee82f0f 100644 --- a/test/jdk/java/util/zip/ZipFile/ReadZip.java +++ b/test/jdk/java/util/zip/ZipFile/ReadZip.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,185 +22,359 @@ */ /* @test - @bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8186464 + @bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8186464 4401122 8322830 @summary Make sure we can read a zip file. - @key randomness @modules jdk.zipfs + @run junit ReadZip */ -import java.io.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URI; -import java.nio.file.Files; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.NoSuchFileException; -import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; -import java.util.List; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.Collections; +import java.util.HexFormat; import java.util.Map; -import java.util.zip.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.junit.jupiter.api.Assertions.*; public class ReadZip { - private static void unreached (Object o) - throws Exception - { - // Should never get here - throw new Exception ("Expected exception was not thrown"); + + // ZIP file produced during tests + private Path zip = Path.of("read-zip.zip"); + + /** + * Create a sample ZIP file for use by tests + * @param name name of the ZIP file to create + * @return a sample ZIP file + * @throws IOException if an unexpected IOException occurs + */ + private Path createZip(String name) throws IOException { + Path zip = Path.of(name); + + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + zo.putNextEntry(new ZipEntry("file.txt")); + zo.write("hello".getBytes(StandardCharsets.UTF_8)); + } + + return zip; } - public static void main(String args[]) throws Exception { - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), - "input.zip"))) { - // Make sure we throw NPE on null objects - try { unreached (zf.getEntry(null)); } - catch (NullPointerException e) {} + /** + * Delete the ZIP file produced after each test method + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } - try { unreached (zf.getInputStream(null)); } - catch (NullPointerException e) {} + /** + * Make sure we throw NPE when calling getEntry or getInputStream with null params + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void nullPointerExceptionOnNullParams() throws IOException { + zip = createZip("null-params.zip"); + try (ZipFile zf = new ZipFile(zip.toFile())) { - ZipEntry ze = zf.getEntry("ReadZip.java"); - if (ze == null) { - throw new Exception("cannot read from zip file"); - } + assertThrows(NullPointerException.class, () -> zf.getEntry(null)); + assertThrows(NullPointerException.class, () -> zf.getInputStream(null)); + + // Sanity check that we can still read an entry + ZipEntry ze = zf.getEntry("file.txt"); + assertNotNull(ze, "cannot read from zip file"); } + } - // Make sure we can read the zip file that has some garbage - // bytes padded at the end. - File newZip = new File(System.getProperty("test.dir", "."), "input2.zip"); - Files.copy(Paths.get(System.getProperty("test.src", ""), "input.zip"), - newZip.toPath(), StandardCopyOption.REPLACE_EXISTING); + /** + * Read the zip file that has some garbage bytes padded at the end + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void bytesPaddedAtEnd() throws IOException { - newZip.setWritable(true); + zip = createZip("bytes-padded.zip"); // pad some bytes - try (OutputStream os = Files.newOutputStream(newZip.toPath(), - StandardOpenOption.APPEND)) { - os.write(1); os.write(3); os.write(5); os.write(7); + try (OutputStream os = Files.newOutputStream(zip, + StandardOpenOption.APPEND)) { + os.write(1); + os.write(3); + os.write(5); + os.write(7); } - try (ZipFile zf = new ZipFile(newZip)) { - ZipEntry ze = zf.getEntry("ReadZip.java"); - if (ze == null) { - throw new Exception("cannot read from zip file"); - } - } finally { - newZip.delete(); + try (ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry ze = zf.getEntry("file.txt"); + assertNotNull(ze, "cannot read from zip file"); + } + } + + /** + * Verify that we can read a comment from the ZIP + * file's 'End of Central Directory' header + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void readZipFileComment() throws IOException { + + // Create a zip file with a comment in the 'End of Central Directory' header + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zos = new ZipOutputStream(out)) { + ZipEntry ze = new ZipEntry("ZipEntry"); + zos.putNextEntry(ze); + zos.write(1); + zos.write(2); + zos.write(3); + zos.write(4); + zos.closeEntry(); + zos.setComment("This is the comment for testing"); } // Read zip file comment - try { - try (FileOutputStream fos = new FileOutputStream(newZip); - ZipOutputStream zos = new ZipOutputStream(fos)) - { - ZipEntry ze = new ZipEntry("ZipEntry"); - zos.putNextEntry(ze); - zos.write(1); zos.write(2); zos.write(3); zos.write(4); - zos.closeEntry(); - zos.setComment("This is the comment for testing"); - } + try (ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry ze = zf.getEntry("ZipEntry"); + assertNotNull(ze, "cannot read entry from zip file"); + assertEquals("This is the comment for testing", zf.getComment()); + } + } - try (ZipFile zf = new ZipFile(newZip)) { - ZipEntry ze = zf.getEntry("ZipEntry"); - if (ze == null) - throw new Exception("cannot read entry from zip file"); - if (!"This is the comment for testing".equals(zf.getComment())) - throw new Exception("cannot read comment from zip file"); - } - } finally { - newZip.delete(); - } - - // Read directory entry - try { - try (FileOutputStream fos = new FileOutputStream(newZip); - ZipOutputStream zos = new ZipOutputStream(fos)) - { - ZipEntry ze = new ZipEntry("directory/"); - zos.putNextEntry(ze); - zos.closeEntry(); - } - try (ZipFile zf = new ZipFile(newZip)) { - ZipEntry ze = zf.getEntry("directory/"); - if (ze == null || !ze.isDirectory()) - throw new RuntimeException("read entry \"directory/\" failed"); - try (InputStream is = zf.getInputStream(ze)) { - is.available(); - } catch (Exception x) { - x.printStackTrace(); - } - - ze = zf.getEntry("directory"); - if (ze == null || !ze.isDirectory()) - throw new RuntimeException("read entry \"directory\" failed"); - try (InputStream is = zf.getInputStream(ze)) { - is.available(); - } catch (Exception x) { - x.printStackTrace(); - } + /** + * Verify that a directory entry can be found using the + * name 'directory/' as well as 'directory/' + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void readDirectoryEntries() throws IOException { + + // Create a ZIP containing some directory entries + try (OutputStream fos = Files.newOutputStream(zip); + ZipOutputStream zos = new ZipOutputStream(fos)) { + // Add a META-INF directory with STORED compression type + ZipEntry metaInf = new ZipEntry("META-INF/"); + metaInf.setMethod(ZipEntry.STORED); + metaInf.setSize(0); + metaInf.setCrc(0); + zos.putNextEntry(metaInf); + + // Add a regular directory + ZipEntry dir = new ZipEntry("directory/"); + zos.putNextEntry(dir); + zos.closeEntry(); + } + + // Verify directory lookups + try (ZipFile zf = new ZipFile(zip.toFile())) { + // Look up 'directory/' using the full name + ZipEntry ze = zf.getEntry("directory/"); + assertNotNull(ze, "read entry \"directory/\" failed"); + assertTrue(ze.isDirectory(), "read entry \"directory/\" failed"); + assertEquals("directory/", ze.getName()); + + try (InputStream is = zf.getInputStream(ze)) { + is.available(); + } catch (Exception x) { + x.printStackTrace(); } - } finally { - newZip.delete(); - } - - // Throw a FNF exception when read a non-existing zip file - try { unreached (new ZipFile( - new File(System.getProperty("test.src", "."), - "input" - + String.valueOf(new java.util.Random().nextInt()) - + ".zip"))); - } catch (NoSuchFileException nsfe) {} - - // read a zip file with ZIP64 end - Path path = Paths.get(System.getProperty("test.dir", ""), "end64.zip"); - try { - URI uri = URI.create("jar:" + path.toUri()); - Map env = Map.of("create", "true", "forceZIP64End", "true"); - try (FileSystem fs = FileSystems.newFileSystem(uri, env)) { - Files.write(fs.getPath("hello"), "hello".getBytes()); + + // Look up 'directory/' without the trailing slash + ze = zf.getEntry("directory"); + assertNotNull(ze, "read entry \"directory\" failed"); + assertTrue(ze.isDirectory(), "read entry \"directory\" failed"); + assertEquals("directory/", ze.getName()); + + try (InputStream is = zf.getInputStream(ze)) { + is.available(); + } catch (Exception x) { + x.printStackTrace(); } - try (ZipFile zf = new ZipFile(path.toFile())) { - if (!"hello".equals(new String(zf.getInputStream(new ZipEntry("hello")) - .readAllBytes(), - US_ASCII))) - throw new RuntimeException("zipfile: read entry failed"); - } catch (IOException x) { - throw new RuntimeException("zipfile: zip64 end failed"); + // Sanity check that also META-INF/ can be looked up with or without the trailing slash + assertNotNull(zf.getEntry("META-INF")); + assertNotNull(zf.getEntry("META-INF/")); + assertEquals(zf.getEntry("META-INF").getName(), + zf.getEntry("META-INF/").getName()); + } + } + + /** + * Throw a NoSuchFileException exception when reading a non-existing zip file + */ + @Test + public void nonExistingFile() { + File nonExistingFile = new File("non-existing-file-f6804460f.zip"); + assertThrows(NoSuchFileException.class, () -> + new ZipFile(nonExistingFile)); + } + + /** + * Read a Zip file with a 'Zip64 End of Central Directory header' which was created + * using ZipFileSystem with the 'forceZIP64End' option. + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void readZip64EndZipFs() throws IOException { + + // Create zip file with Zip64 end + Map env = Map.of("create", "true", "forceZIP64End", "true"); + try (FileSystem fs = FileSystems.newFileSystem(zip, env)) { + Files.write(fs.getPath("hello"), "hello".getBytes()); + } + // Read using ZipFile + try (ZipFile zf = new ZipFile(zip.toFile())) { + try (InputStream in = zf.getInputStream(zf.getEntry("hello"))) { + assertEquals("hello", new String(in.readAllBytes(), StandardCharsets.US_ASCII)); } - try (FileSystem fs = FileSystems.newFileSystem(uri, Map.of())) { - if (!"hello".equals(new String(Files.readAllBytes(fs.getPath("hello"))))) - throw new RuntimeException("zipfs: read entry failed"); - } catch (IOException x) { - throw new RuntimeException("zipfile: zip64 end failed"); + } + // Read using ZipFileSystem + try (FileSystem fs = FileSystems.newFileSystem(zip, Map.of())) { + assertEquals("hello", new String(Files.readAllBytes(fs.getPath("hello")))); + } + } + + /** + * Read a zip file created via Info-ZIP in streaming mode, + * which includes a 'Zip64 End of Central Directory header'. + * + * @throws IOException if an unexpected IOException occurs + * @throws InterruptedException if an unexpected InterruptedException occurs + */ + @Test + public void readZip64EndInfoZIPStreaming() throws IOException, InterruptedException { + // ZIP created using: "echo -n hello | zip zip64.zip -" + // Hex encoded using: "cat zip64.zip | xxd -ps" + byte[] zipBytes = HexFormat.of().parseHex(""" + 504b03042d0000000000c441295886a61036ffffffffffffffff01001400 + 2d010010000500000000000000050000000000000068656c6c6f504b0102 + 1e032d0000000000c441295886a610360500000005000000010000000000 + 000001000000b011000000002d504b06062c000000000000001e032d0000 + 00000000000000010000000000000001000000000000002f000000000000 + 003800000000000000504b06070000000067000000000000000100000050 + 4b050600000000010001002f000000380000000000 + """.replaceAll("\n","") + ); + + Files.write(zip, zipBytes); + + try (ZipFile zf = new ZipFile(this.zip.toFile())) { + try (InputStream in = zf.getInputStream(zf.getEntry("-"))) { + String contents = new String(in.readAllBytes(), StandardCharsets.US_ASCII); + assertEquals("hello", contents); } - } finally { - Files.deleteIfExists(path); - } - - // read a zip file created via "echo hello | zip dst.zip -", which uses - // ZIP64 end record - if (Files.notExists(Paths.get("/usr/bin/zip"))) - return; - try { - Process zip = new ProcessBuilder("zip", path.toString().toString(), "-").start(); - OutputStream os = zip.getOutputStream(); - os.write("hello".getBytes(US_ASCII)); - os.close(); - zip.waitFor(); - if (zip.exitValue() == 0 && Files.exists(path)) { - try (ZipFile zf = new ZipFile(path.toFile())) { - if (!"hello".equals(new String(zf.getInputStream(new ZipEntry("-")) - .readAllBytes()))) - throw new RuntimeException("zipfile: read entry failed"); - } catch (IOException x) { - throw new RuntimeException("zipfile: zip64 end failed"); - } + } + } + + /** + * Check that the available() method overriden by the input stream returned by + * ZipFile.getInputStream correctly returns the number of remaining uncompressed bytes + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void availableShouldReturnRemainingUncompressedBytes() throws IOException { + // The number of uncompressed bytes to write to the sample ZIP entry + final int expectedBytes = 512; + + // Create a sample ZIP with deflated entry of a known uncompressed size + try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) { + zo.putNextEntry(new ZipEntry("file.txt")); + zo.write(new byte[expectedBytes]); + } + + // Verify the behavior of ZipFileInflaterInputStream.available() + try (ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry e = zf.getEntry("file.txt"); + try (InputStream in = zf.getInputStream(e)) { + // Initially, available() should return the full uncompressed size of the entry + assertEquals(expectedBytes, in.available(), + "wrong initial return value of available"); + + // Reading a few bytes should reduce the number of available bytes accordingly + int bytesToRead = 10; + in.read(new byte[bytesToRead]); + assertEquals(expectedBytes - bytesToRead, in.available()); + + // Reading all remaining bytes should reduce the number of available bytes to zero + in.transferTo(OutputStream.nullOutputStream()); + assertEquals(0, in.available()); + + // available on a closed input stream should return zero + in.close(); + assertEquals(0, in.available()); } - } finally { - Files.deleteIfExists(path); } } -} + + /** + * Verify that reading an InputStream from a closed ZipFile + * throws IOException as expected and does not crash the VM. + * See bugs: 4528128 6846616 + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void readAfterClose() throws IOException { + zip = createZip("read-after-close.zip"); + InputStream in; + try (ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry zent = zf.getEntry("file.txt"); + in = zf.getInputStream(zent); + } + + // zf is closed at this point + assertThrows(IOException.class, () -> { + in.read(); + }); + assertThrows(IOException.class, () -> { + in.read(new byte[10]); + }); + assertThrows(IOException.class, () -> { + byte[] buf = new byte[10]; + in.read(buf, 0, buf.length); + }); + assertThrows(IOException.class, () -> { + in.readAllBytes(); + }); + } + + /** + * Verify that ZipFile can open a ZIP file with zero entries + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void noEntries() throws IOException { + // Create a ZIP file with no entries + try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) { + } + + // Open the "empty" ZIP file + try (ZipFile zf = new ZipFile(zip.toFile())) { + // Verify size + assertEquals(0, zf.size()); + + // Verify entry lookup using ZipFile.getEntry() + assertNull(zf.getEntry("file.txt")); + + // Verify iteration using ZipFile.entries() + assertEquals(Collections.emptyList(), Collections.list(zf.entries())); + + // Verify iteration using ZipFile.stream() + assertEquals(Collections.emptyList(), zf.stream().toList()); + } + } +} \ No newline at end of file diff --git a/test/jdk/java/util/zip/ZipFile/ReleaseInflater.java b/test/jdk/java/util/zip/ZipFile/ReleaseInflater.java index f20fc12ecc1..49f676ba555 100644 --- a/test/jdk/java/util/zip/ZipFile/ReleaseInflater.java +++ b/test/jdk/java/util/zip/ZipFile/ReleaseInflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,31 +25,74 @@ * @bug 4214795 * @summary Make sure the same inflater will only be recycled * once. + * @run junit ReleaseInflater */ -import java.io.*; -import java.util.zip.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ReleaseInflater { - public static void main(String[] args) throws Exception { - ZipFile zf = new ZipFile(new File(System.getProperty("test.src"), - "input.jar")); - ZipEntry e = zf.getEntry("ReleaseInflater.java"); + // ZIP file produced in this test + private Path zip = Path.of("release-inflater.zip"); + + /** + * Create a sample ZIP file for use by tests + * @param name name of the ZIP file to create + * @return a sample ZIP file + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) { + zo.putNextEntry(new ZipEntry("file.txt")); + zo.write("helloworld".getBytes(StandardCharsets.UTF_8)); + } + } + + /** + * Delete the ZIP and JAR files produced after each test method + * @throws IOException if an unexpected IOException occurs + */ + + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Verify that the same Inflater is not recycled across input streams + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void recycleInflaterOnlyOnce() throws IOException { + try (ZipFile zf = new ZipFile(zip.toFile())) { + ZipEntry e = zf.getEntry("file.txt"); - InputStream in1 = zf.getInputStream(e); - // close the stream, the inflater will be released - in1.close(); - // close the stream again, should be no-op - in1.close(); + InputStream in1 = zf.getInputStream(e); + // close the stream, the inflater will be released + in1.close(); + // close the stream again, should be no-op + in1.close(); - // create two new streams, allocating inflaters - InputStream in2 = zf.getInputStream(e); - InputStream in3 = zf.getInputStream(e); + // create two new streams, allocating inflaters + InputStream in2 = zf.getInputStream(e); + InputStream in3 = zf.getInputStream(e); - // check to see if they influence each other - if (in2.read() != in3.read()) { - throw new Exception("Stream is corrupted!"); + // check to see if they influence each other + assertEquals(in2.read(), in3.read(), "Stream is corrupted!"); } } } diff --git a/test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java b/test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java index 38199e4694c..eaa3708578e 100644 --- a/test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java +++ b/test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,74 +23,169 @@ /** * @test - * @run testng StreamZipEntriesTest + * @run junit StreamZipEntriesTest * @summary Make sure we can stream entries of a zip file. */ -import java.io.File; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import java.io.IOException; -import java.lang.Object; -import java.lang.System; -import java.util.jar.JarFile; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; public class StreamZipEntriesTest { + // ZIP file produced in this test + private Path zip = Path.of("stream.zip"); + // JAR file produced in this test + private Path jar = Path.of("stream.jar"); + + /** + * Create sample ZIP and JAR files used in in this test + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + zo.putNextEntry(new ZipEntry("entry1.txt")); + zo.write("hello".getBytes(StandardCharsets.UTF_8)); + zo.putNextEntry(new ZipEntry("entry2.txt")); + zo.write("hello".getBytes(StandardCharsets.UTF_8)); + } + + try (OutputStream out = Files.newOutputStream(jar); + ZipOutputStream zo = new ZipOutputStream(out)) { + // A JAR file may start with a META-INF/ directory before the manifest + zo.putNextEntry(new ZipEntry("META-INF/")); + // Write the manifest + zo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF")); + new Manifest().write(zo); + + // Write two regular entries + zo.putNextEntry(new ZipEntry("entry1.txt")); + zo.write("hello".getBytes(StandardCharsets.UTF_8)); + zo.putNextEntry(new ZipEntry("entry2.txt")); + zo.write("hello".getBytes(StandardCharsets.UTF_8)); + } + } + + /** + * Delete the ZIP file produced after each test method + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + Files.deleteIfExists(jar); + } + + /** + * Verify that ZipFile.stream() produces the expected entries + * @throws IOException if an unexpected IOException occurs + */ @Test public void testStreamZip() throws IOException { - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), "input.zip"))) { - zf.stream().forEach(e -> assertTrue(e instanceof ZipEntry)); - zf.stream().forEach(e -> assertEquals(e.toString(), "ReadZip.java")); + Set names = new HashSet<>(Set.of("entry1.txt", "entry2.txt")); + + try (ZipFile zf = new ZipFile(zip.toFile())) { + zf.stream().forEach(e -> { + assertTrue(e instanceof ZipEntry); + String name = e.getName(); + assertNotNull(names.remove(name)); + String toString = e.toString(); + assertEquals(name, toString); + }); + + // Check that all expected names were processed + assertTrue(names.isEmpty()); + // Check that Stream.toArray produces the expected result Object elements[] = zf.stream().toArray(); - assertEquals(1, elements.length); - assertEquals(elements[0].toString(), "ReadZip.java"); + assertEquals(2, elements.length); + assertEquals(elements[0].toString(), "entry1.txt"); + assertEquals(elements[1].toString(), "entry2.txt"); } } + /** + * Verify that JarFile.stream() produces the expected entries + * @throws IOException if an unexpected IOException occurs + */ @Test public void testStreamJar() throws IOException { - try (JarFile jf = new JarFile(new File(System.getProperty("test.src", "."), "input.jar"))) { - jf.stream().forEach(e -> assertTrue(e instanceof JarEntry)); + try (JarFile jf = new JarFile(jar.toFile())) { + Set names = new HashSet<>(Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "entry1.txt", + "entry2.txt" + )); + jf.stream().forEach(e -> { + assertTrue(e instanceof JarEntry); + String name = e.getName(); + assertNotNull(names.remove(name)); + String toString = e.toString(); + assertEquals(name, toString); + } + ); + + // Check that all expected names were processed + assertTrue(names.isEmpty(), "Unprocessed entries: " + names); + + + // Check that Stream.toArray produces the expected result Object elements[] = jf.stream().toArray(); - assertEquals(3, elements.length); + assertEquals(4, elements.length); assertEquals(elements[0].toString(), "META-INF/"); assertEquals(elements[1].toString(), "META-INF/MANIFEST.MF"); - assertEquals(elements[2].toString(), "ReleaseInflater.java"); + assertEquals(elements[2].toString(), "entry1.txt"); + assertEquals(elements[3].toString(), "entry2.txt"); } } + /** + * Calling ZipFile.stream() on a closed ZipFile should throw ISE + * @throws IOException if an unexpected IOException occurs + */ @Test public void testClosedZipFile() throws IOException { - ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), "input.zip")); + ZipFile zf = new ZipFile(zip.toFile()); zf.close(); - try { + assertThrows(IllegalStateException.class, () -> { Stream s = zf.stream(); - fail("Should have thrown IllegalStateException"); - } catch (IllegalStateException e) { - // expected; - } + }); } + /** + * Calling JarFile.stream() on a closed JarFile should throw ISE + * @throws IOException if an unexpected IOException occurs + */ @Test public void testClosedJarFile() throws IOException { - JarFile jf = new JarFile(new File(System.getProperty("test.src", "."), "input.jar")); + JarFile jf = new JarFile(jar.toFile()); jf.close(); - try { + assertThrows(IllegalStateException.class, () -> { Stream s = jf.stream(); - fail("Should have thrown IllegalStateException"); - } catch (IllegalStateException e) { - // expected; - } + }); } } diff --git a/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java b/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java index 8cb1051a87c..0f0b0725b7d 100644 --- a/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java +++ b/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java @@ -25,6 +25,7 @@ * @bug 8317678 * @modules java.base/java.util.zip:open * @summary Fix up hashCode() for ZipFile.Source.Key + * @library /test/lib * @run junit/othervm ZipSourceCache */ @@ -34,6 +35,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.zip.*; +import jdk.test.lib.util.FileUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; @@ -62,7 +64,7 @@ public static void setup() throws Exception { @AfterAll public static void cleanup() throws IOException { - Files.deleteIfExists(Path.of(ZIPFILE_NAME)); + FileUtils.deleteFileIfExistsWithRetry(Path.of(ZIPFILE_NAME)); } /* diff --git a/test/jdk/java/util/zip/ZipFile/crash.jar b/test/jdk/java/util/zip/ZipFile/crash.jar deleted file mode 100644 index 8de20e7582e..00000000000 Binary files a/test/jdk/java/util/zip/ZipFile/crash.jar and /dev/null differ diff --git a/test/jdk/java/util/zip/ZipFile/input.jar b/test/jdk/java/util/zip/ZipFile/input.jar deleted file mode 100644 index f5e6f573317..00000000000 Binary files a/test/jdk/java/util/zip/ZipFile/input.jar and /dev/null differ diff --git a/test/jdk/java/util/zip/ZipFile/input.zip b/test/jdk/java/util/zip/ZipFile/input.zip deleted file mode 100644 index 2ca60bd4c06..00000000000 Binary files a/test/jdk/java/util/zip/ZipFile/input.zip and /dev/null differ diff --git a/test/jdk/javax/print/CustomMediaSizeNameOOMETest.java b/test/jdk/javax/print/CustomMediaSizeNameOOMETest.java new file mode 100644 index 00000000000..bf9f894fe55 --- /dev/null +++ b/test/jdk/javax/print/CustomMediaSizeNameOOMETest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, BELLSOFT. All rights reserved. + * 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 7001133 + * @summary OutOfMemoryError by CustomMediaSizeName implementation + * @run main CustomMediaSizeNameOOMETest + * @run main/timeout=300/othervm -Xmx8m CustomMediaSizeNameOOMETest +*/ + +import javax.print.PrintService; +import javax.print.PrintServiceLookup; + +public class CustomMediaSizeNameOOMETest { + + private static final int MILLIS = 3000; + + public static void main(String[] args) { + + PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); + if (services == null || services.length == 0) { + return; + } + + for (PrintService service : services) { + service.getUnsupportedAttributes(null, null); + } + + long time = System.currentTimeMillis() + MILLIS; + + do { + for (int i = 0; i < 2000; i++) { + for (PrintService service : services) { + service.getAttributes(); + } + } + } while (time > System.currentTimeMillis()); + } +} diff --git a/test/jdk/javax/security/auth/login/modules/JaasModularClientTest.java b/test/jdk/javax/security/auth/login/modules/JaasModularClientTest.java index 2b6bc0519bc..7869c10282a 100644 --- a/test/jdk/javax/security/auth/login/modules/JaasModularClientTest.java +++ b/test/jdk/javax/security/auth/login/modules/JaasModularClientTest.java @@ -184,7 +184,7 @@ private void execute(String args) throws Exception { } return !s.isEmpty(); }).toArray(String[]::new); - OutputAnalyzer out = ProcessTools.executeTestJvm(safeArgs); + OutputAnalyzer out = ProcessTools.executeTestJava(safeArgs); // Handle response. if (out.getExitValue() != 0) { System.out.printf("OUTPUT: %s", out.getOutput()); diff --git a/test/jdk/javax/security/auth/login/modules/JaasModularDefaultHandlerTest.java b/test/jdk/javax/security/auth/login/modules/JaasModularDefaultHandlerTest.java index 2f2c43d03c5..95d2541a190 100644 --- a/test/jdk/javax/security/auth/login/modules/JaasModularDefaultHandlerTest.java +++ b/test/jdk/javax/security/auth/login/modules/JaasModularDefaultHandlerTest.java @@ -168,7 +168,7 @@ private void execute(String args) throws Exception { } return !s.isEmpty(); }).toArray(String[]::new); - OutputAnalyzer out = ProcessTools.executeTestJvm(safeArgs); + OutputAnalyzer out = ProcessTools.executeTestJava(safeArgs); // Handle response. if (out.getExitValue() != 0) { System.out.printf("OUTPUT: %s", out.getOutput()); diff --git a/test/jdk/javax/swing/AbstractButton/5049549/DE1.gif b/test/jdk/javax/swing/AbstractButton/5049549/DE1.gif deleted file mode 100644 index 3c12953f9a5..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/DE1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/DI1.gif b/test/jdk/javax/swing/AbstractButton/5049549/DI1.gif deleted file mode 100644 index a812a358b9d..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/DI1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/DS1.gif b/test/jdk/javax/swing/AbstractButton/5049549/DS1.gif deleted file mode 100644 index 5559452e839..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/DS1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/PR1.gif b/test/jdk/javax/swing/AbstractButton/5049549/PR1.gif deleted file mode 100644 index adefa4459d8..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/PR1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/RO1.gif b/test/jdk/javax/swing/AbstractButton/5049549/RO1.gif deleted file mode 100644 index 68bcf8bed1f..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/RO1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/RS1.gif b/test/jdk/javax/swing/AbstractButton/5049549/RS1.gif deleted file mode 100644 index 09e183eb531..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/RS1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/SE1.gif b/test/jdk/javax/swing/AbstractButton/5049549/SE1.gif deleted file mode 100644 index d408843b337..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/SE1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java b/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java index fd03f6e918d..c24435eb18c 100644 --- a/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java +++ b/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,10 @@ * questions. */ -/* @test - @bug 5049549 7132413 - @summary Tests that the proper icon is used for different states. - @library ../../regtesthelpers - @build Blocker - @run main/manual bug5049549 -*/ - +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.image.BufferedImage; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; @@ -39,17 +35,39 @@ import javax.swing.SwingUtilities; import javax.swing.UIManager; +/* + * @test + * @bug 5049549 7132413 + * @summary Tests that the proper icon is used for different states. + * @library ../../regtesthelpers + * @build Blocker + * @run main/manual bug5049549 + */ public class bug5049549 { - private static ImageIcon DE = new ImageIcon(bug5049549.class.getResource("DE1.gif")); - private static ImageIcon DI = new ImageIcon(bug5049549.class.getResource("DI1.gif")); - private static ImageIcon DS = new ImageIcon(bug5049549.class.getResource("DS1.gif")); - private static ImageIcon RO = new ImageIcon(bug5049549.class.getResource("RO1.gif")); - private static ImageIcon RS = new ImageIcon(bug5049549.class.getResource("RS1.gif")); - private static ImageIcon SE = new ImageIcon(bug5049549.class.getResource("SE1.gif")); - private static ImageIcon PR = new ImageIcon(bug5049549.class.getResource("PR1.gif")); - - private static Blocker blocker = new Blocker(); + private static final Icon DE = generateImage("DE"); + private static final Icon DI = generateImage("DI"); + private static final Icon DS = generateImage("DS"); + private static final Icon RO = generateImage("RO"); + private static final Icon RS = generateImage("RS"); + private static final Icon SE = generateImage("SE"); + private static final Icon PR = generateImage("PR"); + + private static final Blocker blocker = new Blocker(); + + private static Icon generateImage(String str) { + BufferedImage img = new BufferedImage(40, 30, + BufferedImage.TYPE_INT_RGB); + Graphics g = img.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, img.getWidth(), img.getHeight()); + g.setColor(Color.RED); + Font font = new Font(Font.SANS_SERIF, Font.BOLD, 22); + g.setFont(font); + g.drawString(str, 5, 25); + g.dispose(); + return new ImageIcon(img); + } private static class KButton extends JButton { diff --git a/test/jdk/javax/swing/JComboBox/ComboPopupBug.java b/test/jdk/javax/swing/JComboBox/ComboPopupBug.java new file mode 100644 index 00000000000..3a4fb4b8bc7 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/ComboPopupBug.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 8322754 + * @summary Verifies clicking JComboBox during frame closure causes Exception + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ComboPopupBug + */ + +public class ComboPopupBug { + private static final String instructionsText = """ + This test is used to verify that clicking on JComboBox + when frame containing it is about to close should not + cause IllegalStateException. + + A JComboBox is shown with Close button at the bottom. + Click on Close and then click on JComboBox arrow button + to try to show combobox popup. + If IllegalStateException is thrown, test will automatically Fail + otherwise click Pass. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("ComboPopup Instructions") + .instructions(instructionsText) + .testTimeOut(5) + .rows(10) + .columns(35) + .build(); + + SwingUtilities.invokeAndWait(() -> { + JFrame frame = new JFrame("ComboPopup"); + + JComboBox cb = new JComboBox(); + cb.setEditable(true); + cb.addItem("test"); + cb.addItem("test2"); + cb.addItem("test3"); + frame.getContentPane().add(cb, "North"); + + JButton b = new JButton("Close"); + b.addActionListener( + (e)->{ + try { + Thread.sleep(3000); + } + catch (Exception ex) { + } + frame.setVisible(false); + + }); + frame.getContentPane().add(b, "South"); + frame.setSize(200, 200); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index b89a312a67f..d23a948fe9f 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @bug 8320360 * @summary Testing ClassFile limits. * @run junit LimitsTest */ @@ -85,4 +86,10 @@ void testSupportedClassVersion() { var cf = ClassFile.of(); assertThrows(IllegalArgumentException.class, () -> cf.parse(cf.build(ClassDesc.of("ClassFromFuture"), cb -> cb.withVersion(ClassFile.latestMajorVersion() + 1, 0)))); } + + @Test + void testReadingOutOfBounds() { + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}), "reading magic only"); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, 0, 0, 0, 0, 0, 2}), "reading invalid CP size"); + } } diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index 9f5fbe8adca..2c64bacee41 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @summary Testing Signatures. + * @bug 8321540 * @run junit SignaturesTest */ import java.io.IOException; @@ -46,8 +47,11 @@ import java.lang.classfile.Attributes; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Assertions; import static helpers.ClassRecord.assertEqualsDeep; import static java.lang.constant.ConstantDescs.*; +import java.util.function.Consumer; +import java.util.function.Function; class SignaturesTest { @@ -186,4 +190,79 @@ void testClassSignatureClassDesc() throws IOException { assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(), "ClassDesc derived from signature"); } + + @Test + void testBadTypeSignatures() { + """ + LObject + LObject;B + LIterable + LIterable<< + TBar + TBar + B + B;V + X + [LObject + [LIterable + [LIterable<< + [TBar + [TBar + [B + [X + LSet<+Kind<**>;>; + LSet;>; + ()V + """.lines().forEach(assertThrows(Signature::parseFrom)); + } + + @Test + void testBadClassSignatures() { + """ + Ljava/lang/Object;Ljava/lang/Iterable + LObject + LObject;B + LIterable + LIterable<< + TBar + TBar + B + B;V + X + LFoo.It;L + LFoo;LFoo;LBar; + >LFoo; + LFoo<+>; + ()V + """.lines().forEach(assertThrows(ClassSignature::parseFrom)); + } + + @Test + void testBadMethodSignatures() { + """ + LObject; + B + ()V^ + ()V^B + ()V^X + (LObject;) + (LObject)V + ()LIterable + ()LIterable<< + ()TBar + ()TBar;B + (TBar)V + (B)V + (X) + ()X + ()VB + ()LSet<+Kind<**>;>; + (LSet;>;)V + ()V + """.lines().forEach(assertThrows(MethodSignature::parseFrom)); + } + + private Consumer assertThrows(Function parser) { + return s -> Assertions.assertThrows(IllegalArgumentException.class, () -> parser.apply(s), s); + } } diff --git a/test/jdk/jdk/internal/ref/Cleaner/ExitOnThrow.java b/test/jdk/jdk/internal/ref/Cleaner/ExitOnThrow.java index 02346414cd3..7651c92bf77 100644 --- a/test/jdk/jdk/internal/ref/Cleaner/ExitOnThrow.java +++ b/test/jdk/jdk/internal/ref/Cleaner/ExitOnThrow.java @@ -44,9 +44,9 @@ public class ExitOnThrow { public static void main(String[] args) throws Exception { if (args.length == 0) { - ProcessTools.executeTestJvm("--add-exports", "java.base/jdk.internal.ref=ALL-UNNAMED", - "ExitOnThrow", - "-executeCleaner") + ProcessTools.executeTestJava("--add-exports", "java.base/jdk.internal.ref=ALL-UNNAMED", + "ExitOnThrow", + "-executeCleaner") .outputTo(System.out) .errorTo(System.out) .shouldHaveExitValue(1) diff --git a/test/jdk/jdk/jfr/api/consumer/security/TestStreamingRemote.java b/test/jdk/jdk/jfr/api/consumer/security/TestStreamingRemote.java index 6b97613f4ab..f5a32e0b45a 100644 --- a/test/jdk/jdk/jfr/api/consumer/security/TestStreamingRemote.java +++ b/test/jdk/jdk/jfr/api/consumer/security/TestStreamingRemote.java @@ -81,7 +81,7 @@ public static void main(String... args) throws Exception { c[1] = "-Djava.security.policy=" + escapeBackslashes(policy.toString()); c[2] = Test.class.getName(); c[3] = repository; - OutputAnalyzer oa = ProcessTools.executeTestJvm(c); + OutputAnalyzer oa = ProcessTools.executeTestJava(c); oa.shouldContain(SUCCESS); } } diff --git a/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java b/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java index 0df2b5802cf..9c571a514e6 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ public static void main(String[] args) throws Exception { System.out.println("Event:" + event); Events.assertField(event, "phase").notEmpty(); Events.assertField(event, "compileId").atLeast(0); - Events.assertField(event, "phaseLevel").atLeast((short)0).atMost((short)4); + Events.assertField(event, "phaseLevel").atLeast((short)0).atMost((short)5); Events.assertEventThread(event); } } diff --git a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java index 5e08f45cb55..ddbc1206497 100644 --- a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java +++ b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java @@ -283,7 +283,7 @@ private static void launchTest() throws Throwable { "-classpath", classpath, "-javaagent:" + testClassDir + "TestInstrumentation.jar", "jdk.jfr.event.io.TestInstrumentation$TestMain" }; - OutputAnalyzer output = ProcessTools.executeTestJvm(args); + OutputAnalyzer output = ProcessTools.executeTestJava(args); output.shouldHaveExitValue(0); } diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdPreserveRepository.java b/test/jdk/jdk/jfr/jcmd/TestJcmdPreserveRepository.java index f1550e633eb..2ab6bad6259 100644 --- a/test/jdk/jdk/jfr/jcmd/TestJcmdPreserveRepository.java +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdPreserveRepository.java @@ -57,7 +57,7 @@ public static void main(String[] args) throws Throwable { "-Dtest.jdk=" + System.getProperty("test.jdk"), TestProcess.class.getName() }; - OutputAnalyzer output = ProcessTools.executeTestJvm(arguments); + OutputAnalyzer output = ProcessTools.executeTestJava(arguments); output.shouldHaveExitValue(0); Optional p = Files.find(path, 99, (a,b) -> a.getFileName().toString().endsWith(".jfr")).findAny(); if (p.isEmpty()) { diff --git a/test/jdk/jdk/nio/zipfs/CorruptedZipFilesTest.java b/test/jdk/jdk/nio/zipfs/CorruptedZipFilesTest.java new file mode 100644 index 00000000000..39701d073ab --- /dev/null +++ b/test/jdk/jdk/nio/zipfs/CorruptedZipFilesTest.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8316141 8321802 + * @summary test for correct detection and reporting of corrupted zip files + * @run junit CorruptedZipFilesTest + */ + + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipOutputStream; + +import static java.util.zip.ZipFile.*; +import static org.junit.jupiter.api.Assertions.*; + +public class CorruptedZipFilesTest { + + /* + * Byte array holding a valid template ZIP. + * + * The 'good' ZIP file has the following structure: + * + * 0000 LOCAL HEADER #1 04034B50 + * 0004 Extract Zip Spec 14 '2.0' + * 0005 Extract OS 00 'MS-DOS' + * 0006 General Purpose Flag 0808 + * [Bits 1-2] 0 'Normal Compression' + * [Bit 3] 1 'Streamed' + * [Bit 11] 1 'Language Encoding' + * 0008 Compression Method 0008 'Deflated' + * 000A Last Mod Time 567F7D07 'Fri Mar 31 15:40:14 2023' + * 000E CRC 00000000 + * 0012 Compressed Length 00000000 + * 0016 Uncompressed Length 00000000 + * 001A Filename Length 0001 + * 001C Extra Length 0000 + * 001E Filename 'x' + * 001F PAYLOAD ... + * + * 0022 STREAMING DATA HEADER 08074B50 + * 0026 CRC 8CDC1683 + * 002A Compressed Length 00000003 + * 002E Uncompressed Length 00000001 + * + * 0032 CENTRAL HEADER #1 02014B50 + * 0036 Created Zip Spec 14 '2.0' + * 0037 Created OS 00 'MS-DOS' + * 0038 Extract Zip Spec 14 '2.0' + * 0039 Extract OS 00 'MS-DOS' + * 003A General Purpose Flag 0808 + * [Bits 1-2] 0 'Normal Compression' + * [Bit 3] 1 'Streamed' + * [Bit 11] 1 'Language Encoding' + * 003C Compression Method 0008 'Deflated' + * 003E Last Mod Time 567F7D07 'Fri Mar 31 15:40:14 2023' + * 0042 CRC 8CDC1683 + * 0046 Compressed Length 00000003 + * 004A Uncompressed Length 00000001 + * 004E Filename Length 0001 + * 0050 Extra Length 0000 + * 0052 Comment Length 0000 + * 0054 Disk Start 0000 + * 0056 Int File Attributes 0000 + * [Bit 0] 0 'Binary Data' + * 0058 Ext File Attributes 00000000 + * 005C Local Header Offset 00000000 + * 0060 Filename 'x' + * + * 0061 END CENTRAL HEADER 06054B50 + * 0065 Number of this disk 0000 + * 0067 Central Dir Disk no 0000 + * 0069 Entries in this disk 0001 + * 006B Total Entries 0001 + * 006D Size of Central Dir 0000002F + * 0071 Offset to Central Dir 00000032 + * 0075 Comment Length 0000 + * + */ + private static byte[] template; + + // Copy of the template ZIP for modification by each test + private byte[] copy; + + // Litte-endian ByteBuffer for manipulating the ZIP copy + private ByteBuffer buffer; + + // Some well-known locations in the ZIP + private static int endpos, cenpos, locpos; + + // The path used when reading/writing the corrupted ZIP to disk + private Path zip = Path.of("corrupted.zip"); + + /* + * Make a sample ZIP and calculate some known offsets into this ZIP + */ + @BeforeAll + public static void setup() throws IOException { + // Make a ZIP with a single entry + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (ZipOutputStream zos = new ZipOutputStream(out)) { + ZipEntry e = new ZipEntry("x"); + zos.putNextEntry(e); + zos.write((int)'x'); + } + template = out.toByteArray(); + // ByteBuffer for reading fields from the ZIP + ByteBuffer buffer = ByteBuffer.wrap(template).order(ByteOrder.LITTLE_ENDIAN); + + // Calculate the offset of the End of central directory record + endpos = template.length - ENDHDR; + // Look up the offet of the Central directory header + cenpos = buffer.getShort(endpos + ENDOFF); + // Look up the offset of the corresponding Local file header + locpos = buffer.getShort(cenpos + CENOFF); + + // Run some sanity checks on the valid ZIP: + assertEquals(ENDSIG, buffer.getInt(endpos),"Where's ENDSIG?"); + assertEquals(CENSIG, buffer.getInt(cenpos),"Where's CENSIG?"); + assertEquals(LOCSIG, buffer.getInt(locpos),"Where's LOCSIG?"); + assertEquals(buffer.getShort(cenpos+CENNAM), + buffer.getShort(locpos+LOCNAM), + "Name field length mismatch"); + assertEquals(buffer.getShort(cenpos+CENEXT), + buffer.getShort( locpos+LOCEXT), + "Extra field length mismatch"); + } + + /* + * Make a copy safe to modify by each test + */ + @BeforeEach + public void makeCopy() { + copy = template.clone(); + buffer = ByteBuffer.wrap(copy).order(ByteOrder.LITTLE_ENDIAN); + } + + /* + * Delete the ZIP file produced after each test method + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /* + * A ZipException is thrown when the 'End of Central Directory' + * (END) header has a CEN size exceeding past the offset of the END record + */ + @Test + public void excessiveCENSize() throws IOException { + buffer.putInt(endpos+ENDSIZ, 0xff000000); + assertZipException(".*bad central directory size.*"); + } + + /* + * A ZipException is thrown when the 'End of Central Directory' + * (END) header has a CEN offset with an invalid value. + */ + @Test + public void excessiveCENOffset() throws IOException { + buffer.putInt(endpos+ENDOFF, 0xff000000); + assertZipException(".*bad central directory offset.*"); + } + + /* + * A ZipException is thrown when a CEN header has an unexpected signature + */ + @Test + public void invalidCENSignature() throws IOException { + int existingSignature = buffer.getInt(cenpos); + buffer.putInt(cenpos, existingSignature +1); + assertZipException(".*bad signature.*"); + } + + /* + * A ZipException is thrown when a CEN header has the + * 'general purpose bit flag 0' ('encrypted') set. + */ + @Test + public void encryptedEntry() throws IOException { + copy[cenpos+CENFLG] |= 1; + assertZipException(".*encrypted entry.*"); + } + + /* + * A ZipException is thrown when a CEN header has a file name + * length which makes the CEN header overflow into the + * 'End of central directory' record. + */ + @Test + public void excessiveFileNameLength() throws IOException { + short existingNameLength = buffer.getShort(cenpos + CENNAM); + buffer.putShort(cenpos+CENNAM, (short) (existingNameLength + 1)); + assertZipException(".*bad header size.*"); + } + + /* + * A ZipException is thrown when a CEN header has a + * file name length which makes the CEN header overflow into the + * 'End of central directory' record. + */ + @Test + public void excessiveFileNameLength2() throws IOException { + buffer.putShort(cenpos + CENNAM, (short) 0xfdfd); + assertZipException(".*bad header size.*"); + } + + /* + * A ZipException is thrown if a CEN header has an + * extra field length which makes the CEN header overflow into the + * End of central directory record. + */ + @Test + public void excessiveExtraFieldLength() throws IOException { + buffer.put(cenpos+CENEXT, (byte) 0xff); + buffer.put(cenpos+CENEXT+1, (byte) 0xff); + assertZipException(".*bad header size.*"); + } + + /* + * A ZipException is thrown by Zip FS if a CEN header has an + * extra field length which makes the CEN header overflow into the + * End of central directory record. + */ + @Test + public void excessiveExtraFieldLength2() throws IOException { + buffer.putShort(cenpos+CENEXT, (short) 0xfdfd); + assertZipException(".*bad header size.*"); + } + + /* + * A ZipException is thrown when a CEN header has a comment length + * which overflows into the 'End of central directory' record + */ + @Test + public void excessiveCommentLength() throws IOException { + short existingCommentLength = buffer.getShort(cenpos + CENCOM); + buffer.putShort(cenpos+CENCOM, (short) (existingCommentLength + 1)); + assertZipException(".*bad header size.*"); + } + + /* + * A ZipException is thrown when a CEN header has a + * compression method field which is unsupported by the implementation + */ + @Test + public void unsupportedCompressionMethod() throws IOException { + copy[cenpos+CENHOW] = 2; + assertZipException(".*unsupported compression method.*"); + } + + /* + * A ZipException is thrown when a LOC header has an unexpected signature + */ + @Test + public void invalidLOCSignature() throws IOException { + int existingSignature = buffer.getInt(locpos); + buffer.putInt(locpos, existingSignature +1); + assertZipException(".*bad signature.*"); + } + + /* + * Assert that opening a ZIP file and consuming the entry's + * InputStream using the ZipFile API fails with a ZipException + * with a message matching the given pattern. + * + * The ZIP file opened is the contents of the 'copy' byte array. + */ + void assertZipException(String msgPattern) throws IOException { + + Files.write(zip, copy); + + ZipException ex = assertThrows(ZipException.class, () -> { + try (FileSystem fs = FileSystems.newFileSystem(zip, Map.of())) { + Path p = fs.getPath("x"); + try (InputStream is = Files.newInputStream(p)) { + is.transferTo(OutputStream.nullOutputStream()); + } + } + }); + assertTrue(ex.getMessage().matches(msgPattern), + "Unexpected ZipException message: " + ex.getMessage()); + } +} diff --git a/test/jdk/jdk/nio/zipfs/TestPosix.java b/test/jdk/jdk/nio/zipfs/TestPosix.java index f629dfef222..1fa3bdf2d7b 100644 --- a/test/jdk/jdk/nio/zipfs/TestPosix.java +++ b/test/jdk/jdk/nio/zipfs/TestPosix.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, SAP SE. All rights reserved. + * Copyright (c) 2019, 2024, SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,16 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.GroupPrincipal; -import java.nio.file.attribute.PosixFileAttributeView; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.nio.file.attribute.UserPrincipal; +import java.nio.file.attribute.*; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import java.time.Instant; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -49,7 +42,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE; import static java.nio.file.attribute.PosixFilePermission.GROUP_READ; @@ -60,11 +53,11 @@ import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE; import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @test @@ -72,8 +65,8 @@ * @summary Test POSIX ZIP file operations. * @modules jdk.zipfs * jdk.jartool - * @run testng TestPosix - * @run testng/othervm/java.security.policy=test.policy.posix TestPosix + * @run junit TestPosix + * @run junit/othervm/java.security.policy=test.policy.posix TestPosix */ public class TestPosix { private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") @@ -364,7 +357,7 @@ private void checkEntry(Path file, checkExpects expected) { fail("Caught IOException reading file attributes (basic) " + name + ": " + e.getMessage()); } } - assertEquals(Files.isDirectory(file), ei.isDir, "Unexpected directory attribute for:" + System.lineSeparator() + attrs); + assertEquals(ei.isDir, Files.isDirectory(file), "Unexpected directory attribute for:" + System.lineSeparator() + attrs); if (expected == checkExpects.contentOnly) { return; @@ -402,7 +395,7 @@ private void doCheckEntries(Path path, checkExpects expected) throws IOException }); } System.out.println("Number of entries: " + entries.get() + "."); - assertEquals(entries.get(), entriesCreated, "File contained wrong number of entries."); + assertEquals(entriesCreated, entries.get(), "File contained wrong number of entries."); } private void checkEntries(FileSystem fs, checkExpects expected) throws IOException { @@ -429,7 +422,7 @@ private void comparePermissions(Set expected, Set { + Path path = fs.getPath("hello.txt"); + // Set permissions to their current value + Files.setPosixFilePermissions(path, Files.getPosixFilePermissions(path)); + }); + } + + /** + * Verify that a non-POSIX operation such as Files.setLastModifiedTime + * does not change the 'external file attributes' field. + * + * @throws IOException if an unexpected IOException occurs + */ + @Test + public void setLastModifiedTimeShouldNotChangeExternalFileAttribute() throws IOException { + assertExternalFileAttributeUnchanged(fs -> { + Path path = fs.getPath("hello.txt"); + Files.setLastModifiedTime(path, FileTime.from(Instant.now())); + }); + } + + // Represents an operation performed on a FileSystem + static interface FileSystemOperation { + void accept(FileSystem fileSystem) throws IOException; + } + + /** + * Assert that running the given operation on a ZipFileSystem does not + * change the 'external file attributes' value of the 'hello.txt' entry + * @param action the action to run on the file system + * + * @throws IOException if an unexpected IOException occurs + */ + private void assertExternalFileAttributeUnchanged(FileSystemOperation action) throws IOException { + /* + * The ZIP test vector used here is created using: + * % touch hello.txt + * % chmod u+s hello.txt # setuid + * % chmod g+s hello.txt # setgid + * % chmod +t hello.txt # sticky + * % zip hello.zip hello.txt + * % cat hello.zip | xxd -ps + */ + byte[] zip = HexFormat.of().parseHex(""" + 504b03040a0000000000d994945700000000000000000000000009001c00 + 68656c6c6f2e7478745554090003aa268365aa26836575780b000104f501 + 00000414000000504b01021e030a0000000000d994945700000000000000 + 0000000000090018000000000000000000a48f0000000068656c6c6f2e74 + 78745554050003aa26836575780b000104f50100000414000000504b0506 + 00000000010001004f000000430000000000 + """.replaceAll("\n","")); + + // Expected bit values of the 'external file attributes' CEN field in the ZIP above + String expectedBits = "1000111110100100"; + // ^^^^ file type: 1000 (regular file) + // ^ setuid: ON + // ^ setgid: ON + // ^ sticky: ON + // ^^^^^^^^^ rwxr--r-- (9 bits) + + // Sanity check that 'external file attributes' has the expected value + verifyExternalFileAttribute(zip, expectedBits); + + + Path zipFile = Path.of("preserve-external-file-attrs.zip"); + Files.write(zipFile, zip); + + // Run the provided action on the ZipFileSystem + try (FileSystem fs = FileSystems.newFileSystem(zipFile, ENV_POSIX)) { + action.accept(fs); + } + // Running the action should not change the 'external file attributes' value + verifyExternalFileAttribute(Files.readAllBytes(zipFile), expectedBits); + } + + /** + * Verify that the first 16 bits of the CEN field 'external file attributes' matches + * a given bit string + * @param zip the ZIP file to parse + * @param expectedBits a string of '0' or '1' representing the expected bits + */ + private void verifyExternalFileAttribute(byte[] zip, String expectedBits) { + // Buffer to help parse the ZIP + ByteBuffer buffer = ByteBuffer.wrap(zip).order(ByteOrder.LITTLE_ENDIAN); + // Look up offset of first CEN header from the END header + int cenOff = buffer.getInt(buffer.capacity() - ZipFile.ENDHDR + ZipFile.ENDOFF); + // We're interested in the first 16 'unix' bits of the 32-bit 'external file attributes' field + int externalFileAttr = (buffer.getInt(cenOff + ZipFile.CENATX) >> 16) & 0xFFFF; + + // Verify that the expected bits are set + assertEquals(expectedBits, Integer.toBinaryString(externalFileAttr), + "The 'external file attributes' field does not match the expected value:"); } } diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java index 31db9d1a380..22868ffaf3c 100644 --- a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java @@ -52,7 +52,7 @@ /* * @test - * @bug 8012229 8300725 8279216 + * @bug 8012229 8300725 8279216 8323210 * @summary one more test to check the alpha channel */ public final class ColCvtAlphaDifferentSrcDst { diff --git a/test/jdk/sun/security/mscapi/DupAlias.java b/test/jdk/sun/security/mscapi/DupAlias.java new file mode 100644 index 00000000000..84c70cbbee2 --- /dev/null +++ b/test/jdk/sun/security/mscapi/DupAlias.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import jdk.test.lib.Asserts; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.x509.X500Name; + +import java.security.KeyStore; +import java.security.MessageDigest; +import java.security.cert.X509Certificate; +import java.util.HexFormat; + +/** + * @test + * @bug 8187634 + * @requires os.family == "windows" + * @library /test/lib + * @modules java.base/sun.security.tools.keytool + * java.base/sun.security.x509 + * @summary getCertificateAlias should return correct alias + */ +public class DupAlias { + public static void main(String[] args) throws Exception { + + String nn = "8187634"; + String na = nn + "a"; + String nb = nn + "b"; + String n1 = nn + " (1)"; + + CertAndKeyGen g = new CertAndKeyGen("EC", "SHA256withECDSA"); + g.generate(-1); + X509Certificate a = g.getSelfCertificate(new X500Name("CN=" + na), 1000); + g.generate(-1); + X509Certificate b = g.getSelfCertificate(new X500Name("CN=" + nb), 1000); + + KeyStore ks = KeyStore.getInstance("Windows-MY-CURRENTUSER"); + try { + ks.load(null, null); + ks.deleteEntry(na); + ks.deleteEntry(nb); + ks.deleteEntry(nn); + ks.deleteEntry(n1); + ks.setCertificateEntry(na, a); + ks.setCertificateEntry(nb, b); + + ps(String.format(""" + $cert = Get-Item Cert:/CurrentUser/My/%s; + $cert.FriendlyName = %s; + $cert = Get-Item Cert:/CurrentUser/My/%s; + $cert.FriendlyName = %s; + """, thumbprint(a), nn, thumbprint(b), nn)); + + ks.load(null, null); + Asserts.assertFalse(ks.containsAlias(na)); + Asserts.assertFalse(ks.containsAlias(nb)); + Asserts.assertEquals(ks.getCertificateAlias(ks.getCertificate(nn)), nn); + Asserts.assertEquals(ks.getCertificateAlias(ks.getCertificate(n1)), n1); + } finally { + ks.deleteEntry(na); + ks.deleteEntry(nb); + ks.deleteEntry(nn); + ks.deleteEntry(n1); + } + } + + static void ps(String f) throws Exception { + ProcessBuilder pb = new ProcessBuilder("powershell", "-Command", f); + pb.inheritIO(); + if (pb.start().waitFor() != 0) { + throw new RuntimeException("Failed"); + } + } + + static String thumbprint(X509Certificate c) throws Exception { + return HexFormat.of().formatHex( + MessageDigest.getInstance("SHA-1").digest(c.getEncoded())); + } +} diff --git a/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java b/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java index b5ca601c011..11a6a781e01 100644 --- a/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java +++ b/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java @@ -40,7 +40,7 @@ public class ReadConfInUTF16Env { public void testReadConfInUTF16Env() throws Exception { String[] testCommand = new String[] { "-Dfile.encoding=UTF-16", TestSunPKCS11Provider.class.getName()}; - ProcessTools.executeTestJvm(testCommand).shouldHaveExitValue(0); + ProcessTools.executeTestJava(testCommand).shouldHaveExitValue(0); } static class TestSunPKCS11Provider { diff --git a/test/jdk/sun/security/rsa/WithoutNULL.java b/test/jdk/sun/security/rsa/WithoutNULL.java new file mode 100644 index 00000000000..64cf831099d --- /dev/null +++ b/test/jdk/sun/security/rsa/WithoutNULL.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8320597 + * @summary Verify RSA signature with omitted digest params (should be encoded as NULL) + * for backward compatibility + */ +import java.security.KeyFactory; +import java.security.Signature; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class WithoutNULL { + public static void main(String[] args) throws Exception { + + // A 1024-bit RSA public key + byte[] key = Base64.getMimeDecoder().decode(""" + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrfTrEm4KvdFSpGAM7InrFEzALTKdphT9fK6Gu + eVjHtKsuCSEaULCdjhJvPpFK40ONr1JEC1Ywp1UYrfBBdKunnbDZqNZL1cFv+IzF4Yj6JO6pOeHi + 1Zpur1GaQRRlYTvzmyWY/AATQDh8JfKObNnDVwXeezFODUG8h5+XL1ZXZQIDAQAB"""); + + // A SHA1withRSA signature on an empty input where the digestAlgorithm + // inside DigestInfo does not have a parameters field. + byte[] sig = Base64.getMimeDecoder().decode(""" + D1FpiT44WEXlDfYK880bdorLO+e9qJVXZWiBgqs9dfK7lYQwyEt9dL23mbUAKm5TVEj2ZxtHkEvk + b8oaWkxk069jDTM1RhllPJZkAjeQRbw4gkg4N6wKZz9B/jdSRMNJg/b9QdRYZOHOBxsEHMbUREPV + DoCOLaxB8eIXX0EWkiE="""); + + Signature s = Signature.getInstance("SHA1withRSA", "SunRsaSign"); + s.initVerify(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(key))); + if (!s.verify(sig)) { + throw new RuntimeException("Does not verify"); + } + } +} diff --git a/test/jdk/sun/security/ssl/CertPathRestrictions/TLSRestrictions.java b/test/jdk/sun/security/ssl/CertPathRestrictions/TLSRestrictions.java index b9fb72b8faf..476dc954884 100644 --- a/test/jdk/sun/security/ssl/CertPathRestrictions/TLSRestrictions.java +++ b/test/jdk/sun/security/ssl/CertPathRestrictions/TLSRestrictions.java @@ -231,7 +231,7 @@ static void testConstraint(String[] trustNames, String[] certNames, // Run client on another JVM so that its properties cannot be in conflict // with server's. - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( "-Dcert.dir=" + CERT_DIR, "-Djava.security.debug=certpath", "-classpath", diff --git a/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java b/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java index 1ce50662f46..7632fcf462f 100644 --- a/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java +++ b/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java @@ -93,7 +93,7 @@ public class DebugReportsOneExtraByte extends SSLEngineTemplate { public static void main(String args[]) throws Exception { if (args.length == 0) { - OutputAnalyzer output = ProcessTools.executeTestJvm( + OutputAnalyzer output = ProcessTools.executeTestJava( "-Dtest.src=" + System.getProperty("test.src"), "-Djavax.net.debug=all", "DebugReportsOneExtraByte", "p"); output.shouldContain("WRITE: TLSv1 application_data, length = 8"); diff --git a/test/jdk/sun/security/ssl/SSLLogger/LoggingFormatConsistency.java b/test/jdk/sun/security/ssl/SSLLogger/LoggingFormatConsistency.java index c614ca62f29..5cfa9c9a680 100644 --- a/test/jdk/sun/security/ssl/SSLLogger/LoggingFormatConsistency.java +++ b/test/jdk/sun/security/ssl/SSLLogger/LoggingFormatConsistency.java @@ -50,7 +50,7 @@ public class LoggingFormatConsistency extends SSLSocketTemplate { public static void main(String[] args) throws Exception { if (args.length != 0) { // A non-empty set of arguments occurs when the "runTest" argument - // is passed to the test via ProcessTools::executeTestJvm. + // is passed to the test via ProcessTools::executeTestJava. // // This is done because an OutputAnalyzer is unable to read // the output of the current running JVM, and must therefore create @@ -71,7 +71,7 @@ public static void main(String[] args) throws Exception { System.out.println("TESTING " + expectedTLSVersion); var activeTLSProtocol = "-Djdk.tls.client.protocols=" + expectedTLSVersion; - var output = ProcessTools.executeTestJvm( + var output = ProcessTools.executeTestJava( testSrc, activeTLSProtocol, javaxNetDebug, diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/IgnorableExceptionMessages.java b/test/jdk/sun/security/ssl/SSLSocketImpl/IgnorableExceptionMessages.java index 708b8f0d11b..a1c9cad2271 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/IgnorableExceptionMessages.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/IgnorableExceptionMessages.java @@ -49,7 +49,7 @@ public class IgnorableExceptionMessages extends SSLSocketTemplate { public static void main(String[] args) throws Exception { if (args.length > 0) { // A non-empty set of arguments occurs when the "runTest" argument - // is passed to the test via ProcessTools::executeTestJvm. + // is passed to the test via ProcessTools::executeTestJava. // // This is done because an OutputAnalyzer is unable to read // the output of the current running JVM, and must therefore create @@ -67,7 +67,7 @@ public static void main(String[] args) throws Exception { className, extraArgument); - OutputAnalyzer output = ProcessTools.executeTestJvm(jvmArgs); + OutputAnalyzer output = ProcessTools.executeTestJava(jvmArgs); if (output.getExitValue() != 0) { output.asLines().forEach(System.out::println); // No need to dump the output unless the test fails diff --git a/test/jdk/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java b/test/jdk/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java index ccc4b405147..9c9a8590ac7 100644 --- a/test/jdk/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java +++ b/test/jdk/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java @@ -120,7 +120,7 @@ public static void main(String[] args) throws Throwable { "-Djava.security.policy=" + TEST_SRC + File.separator + POLICY_FILE, "version.Main"}; - ProcessTools.executeTestJvm(cmd) + ProcessTools.executeTestJava(cmd) .shouldHaveExitValue(0) .shouldContain(VERSION_MESSAGE); } diff --git a/test/jdk/sun/security/tools/keytool/LineEndings.java b/test/jdk/sun/security/tools/keytool/LineEndings.java new file mode 100644 index 00000000000..621102ae73c --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/LineEndings.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.ByteArrayOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * @test + * @bug 8202598 + * @summary PEM outputs should have consistent line endings + * @library /test/lib + */ + +public class LineEndings { + + public static void main(String[] args) throws Exception { + keytool("-genkeypair -dname CN=A -keyalg ec"); + + keytool("-certreq -file a.csr -rfc"); + checkFile("a.csr"); + + keytool("-exportcert -file a.crt -rfc"); + checkFile("a.crt"); + + keytool("-gencrl -id 1 -rfc -file a.crl"); + checkFile("a.crl"); + + // `keytool -printcrl` shows "Verified by ..." at the end. Remove it. + String print = keytool("-printcrl -file a.crl -rfc").getStdout(); + print = print.substring(0, print.indexOf("Verified by")); + Files.writeString(Path.of("print"), print); + checkFile("print"); + } + + private static OutputAnalyzer keytool(String cmd) throws Exception { + return SecurityTools.keytool( + "-keystore ks -storepass changeit -alias a " + cmd) + .shouldHaveExitValue(0); + } + + // Make sure only CRLF is used inside the file. + private static void checkFile(String name) throws Exception { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (byte b : Files.readAllBytes(Path.of(name))) { + // Collect all non-printable bytes in an array + if (b < 32) bout.write(b); + } + // There should only be a series of CRLFs left + byte[] endings = bout.toByteArray(); + Asserts.assertTrue(endings.length > 4, "Too empty"); + Asserts.assertTrue(endings.length % 2 == 0, + "Length is " + endings.length); + for (int i = 0; i < endings.length; i += 2) { + Asserts.assertEquals(endings[i], (byte)'\r', + "Byte at " + i + " is not CR"); + Asserts.assertEquals(endings[i + 1], (byte)'\n', + "Byte at " + (i + 1) + " is not LF"); + } + } +} diff --git a/test/jdk/sun/security/util/Resources/early/EarlyResources.java b/test/jdk/sun/security/util/Resources/early/EarlyResources.java index 12da50e311f..3ee0a9f576c 100644 --- a/test/jdk/sun/security/util/Resources/early/EarlyResources.java +++ b/test/jdk/sun/security/util/Resources/early/EarlyResources.java @@ -42,7 +42,7 @@ public static void main(String[] args) throws Exception { String fs = File.separator; String policyPath = testSrc + fs + "malformed.policy"; - OutputAnalyzer out = ProcessTools.executeTestJvm( + OutputAnalyzer out = ProcessTools.executeTestJava( "-Djava.security.manager", "-Djava.security.policy=" + policyPath, "EarlyResources$TestMain"); diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index eb56c087ad6..a468f6b1f1b 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,10 @@ /* * @test - * @bug 8181157 8202537 8234347 8236548 8261279 + * @bug 8181157 8202537 8234347 8236548 8261279 8322647 * @modules jdk.localedata - * @summary Checks CLDR time zone names are generated correctly at runtime + * @summary Checks CLDR time zone names are generated correctly at + * either build or runtime * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest */ @@ -45,8 +46,8 @@ @Test public class TimeZoneNamesTest { - @DataProvider(name="noResourceTZs") - Object[][] data() { + @DataProvider + Object[][] sampleTZs() { return new Object[][] { // tzid, locale, style, expected @@ -174,11 +175,49 @@ Object[][] data() { "UTC+03:00", "heure : Istanbul", "UTC+03:00"}, + + // Short names derived from TZDB at build time + {"Europe/Lisbon", Locale.US, "Western European Standard Time", + "WET", + "Western European Summer Time", + "WEST", + "Western European Time", + "WET"}, + {"Atlantic/Azores", Locale.US, "Azores Standard Time", + "GMT-01:00", + "Azores Summer Time", + "GMT", + "Azores Time", + "GMT-01:00"}, + {"Australia/Perth", Locale.US, "Australian Western Standard Time", + "AWST", + "Australian Western Daylight Time", + "AWDT", + "Western Australia Time", + "AWT"}, + {"Africa/Harare", Locale.US, "Central Africa Time", + "CAT", + "Harare Daylight Time", + "CAT", + "Harare Time", + "CAT"}, + {"Europe/Dublin", Locale.US, "Greenwich Mean Time", + "GMT", + "Irish Standard Time", + "IST", + "Dublin Time", + "GMT"}, + {"Pacific/Gambier", Locale.US, "Gambier Time", + "GMT-09:00", + "Gambier Daylight Time", + "GMT-09:00", + "Gambier Time", + "GMT-09:00"}, }; } - @Test(dataProvider="noResourceTZs") + @Test(dataProvider="sampleTZs") public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, String ldst, String sdst, String lgen, String sgen) { // Standard time assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale), lstd); @@ -197,16 +236,14 @@ public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, S @Test public void test_getZoneStrings() { assertFalse( - Arrays.stream(Locale.getAvailableLocales()) + Locale.availableLocales() .limit(30) .peek(l -> System.out.println("Locale: " + l)) .map(l -> DateFormatSymbols.getInstance(l).getZoneStrings()) - .flatMap(zs -> Arrays.stream(zs)) + .flatMap(Arrays::stream) .peek(names -> System.out.println(" tz: " + names[0])) - .flatMap(names -> Arrays.stream(names)) - .filter(name -> Objects.isNull(name) || name.isEmpty()) - .findAny() - .isPresent(), + .flatMap(Arrays::stream) + .anyMatch(name -> Objects.isNull(name) || name.isEmpty()), "getZoneStrings() returned array containing non-empty string element(s)"); } } diff --git a/test/jdk/tools/jar/InputFilesTest.java b/test/jdk/tools/jar/InputFilesTest.java index 3dc08293a76..6a0a7e29021 100644 --- a/test/jdk/tools/jar/InputFilesTest.java +++ b/test/jdk/tools/jar/InputFilesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8165944 + * @bug 8165944 8318971 * @summary test several jar tool input file scenarios with variations on -C * options with/without a --release option. Some input files are * duplicates that sometimes cause exceptions and other times do not, @@ -153,6 +153,84 @@ public void test6() throws IOException { jar("cf test.jar --release 9 -C test1 a -C test2 a"); } + /** + * Containing non-existent file in the file list + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testNonExistentFileInput() throws IOException { + touch("existingTestFile.txt"); + onCompletion = () -> rm("existingTestFile.txt"); + try { + jar("cf test.jar existingTestFile.txt nonExistentTestFile.txt"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + Assert.assertEquals(e.getMessage().trim(), "nonExistentTestFile.txt : no such file or directory"); + Assert.assertTrue(Files.notExists(Path.of("test.jar")), "Jar file should not be created."); + } + } + + /** + * With @File as a part of jar command line, where the File is containing one or more + * non-existent files or directories + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testNonExistentFileInputClassList() throws IOException { + touch("existingTestFile.txt"); + touch("classes.list"); + Files.writeString(Path.of("classes.list"), """ + existingTestFile.txt + nonExistentTestFile.txt + nonExistentDirectory + """); + onCompletion = () -> rm("existingTestFile.txt classes.list"); + try { + jar("cf test.jar @classes.list"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + String msg = e.getMessage().trim(); + Assert.assertTrue(msg.contains("nonExistentTestFile.txt : no such file or directory")); + Assert.assertTrue(msg.trim().contains("nonExistentDirectory : no such file or directory")); + Assert.assertTrue(Files.notExists(Path.of("test.jar")), "Jar file should not be created."); + } + + } + + /** + * Create a jar file; then with @File as a part of jar command line, where the File is containing one or more + * non-existent files or directories + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testUpdateNonExistentFileInputClassList() throws IOException { + touch("existingTestFileUpdate.txt"); + touch("existingTestFileUpdate2.txt"); + touch("classesUpdate.list"); + Files.writeString(Path.of("classesUpdate.list"), """ + existingTestFileUpdate2.txt + nonExistentTestFileUpdate.txt + nonExistentDirectoryUpdate + """); + onCompletion = () -> rm("existingTestFileUpdate.txt existingTestFileUpdate2.txt " + + "classesUpdate.list testUpdate.jar"); + try { + jar("cf testUpdate.jar existingTestFileUpdate.txt"); + Assert.assertTrue(Files.exists(Path.of("testUpdate.jar"))); + jar("uf testUpdate.jar @classesUpdate.list"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + String msg = e.getMessage().trim(); + Assert.assertFalse(msg.contains("existingTestFileUpdate.txt : no such file or directory")); + Assert.assertTrue(msg.contains("nonExistentTestFileUpdate.txt : no such file or directory")); + Assert.assertTrue(msg.trim().contains("nonExistentDirectoryUpdate : no such file or directory")); + } + + } + private Stream mkpath(String... args) { return Arrays.stream(args).map(d -> Paths.get(".", d.split("/"))); } diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java new file mode 100644 index 00000000000..ca7e2bc5f30 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.test.lib.compiler.CompilerUtils; +import jdk.test.lib.util.FileUtils; + +import static jdk.test.lib.process.ProcessTools.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @test + * @bug 8322809 + * @library /test/lib + * @modules jdk.compiler jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils + * jdk.test.lib.process.ProcessTools + * jdk.test.lib.util.FileUtils + * ModuleMainClassTest + * @run junit ModuleMainClassTest + */ + +public class ModuleMainClassTest { + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Path.of(TEST_SRC, "src"); + private static final Path MODS_DIR = Path.of("mods"); + private static final Path JMODS_DIR = Path.of("jmods"); + + private static final Path IMAGE = Path.of("image"); + + // the module names are sorted by the plugin and so these names cover + // the cases that are before and after the elements of `jdk.*` modules + // with main classes + private static String[] modules = new String[] {"com.foo", "net.foo"}; + + private static boolean hasJmods() { + if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) { + System.err.println("Test skipped. NO jmods directory"); + return false; + } + return true; + } + + @BeforeAll + public static void compileAll() throws Throwable { + if (!hasJmods()) return; + + for (String mn : modules) { + Path msrc = SRC_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(msrc, MODS_DIR, + "--module-source-path", SRC_DIR.toString(), + "--add-exports", "java.base/jdk.internal.module=" + mn)); + } + + if (Files.exists(IMAGE)) { + FileUtils.deleteFileTreeUnchecked(IMAGE); + } + + // create JMOD files + Files.createDirectories(JMODS_DIR); + Stream.of(modules).forEach(mn -> + assertTrue(jmod("create", + "--class-path", MODS_DIR.resolve(mn).toString(), + "--main-class", mn + ".Main", + JMODS_DIR.resolve(mn + ".jmod").toString()) == 0) + ); + + // the run-time image created will have 4 modules with main classes + createImage(IMAGE, "com.foo"); + } + + @Test + public void testComFoo() throws Exception { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-m", "com.foo") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + @Test + public void testNetFoo() throws Exception { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-m", "net.foo") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> new RuntimeException("jlink tool not found")); + + static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") + .orElseThrow(() -> new RuntimeException("jmod tool not found")); + + private static void createImage(Path outputDir, String... modules) throws Throwable { + assertTrue(JLINK_TOOL.run(System.out, System.out, + "--output", outputDir.toString(), + "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")), + "--module-path", JMODS_DIR.toString()) == 0); + } + + private static int jmod(String... options) { + System.out.println("jmod " + Arrays.asList(options)); + return JMOD_TOOL.run(System.out, System.out, options); + } +} diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java new file mode 100644 index 00000000000..f8b230647fa --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.foo; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.stream.Stream; + +/** + * Sanity test if SystemModules pre-resolved at link-time for com.foo + * with main class is loaded properly. + */ +public class Main { + public static void main(String... args) throws Exception { + ModuleDescriptor md = Main.class.getModule().getDescriptor(); + System.out.println(md); + + checkMainClass("com.foo", "com.foo.Main"); + checkMainClass("net.foo", "net.foo.Main"); + Stream.of("jdk.httpserver", "jdk.jfr").forEach(mn -> + ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass() + .orElseThrow(() -> new RuntimeException(mn + " no main class")) + ); + } + + static void checkMainClass(String mn, String mainClass) { + String cn = ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass().get(); + if (!cn.equals(mainClass)) { + throw new RuntimeException("Mismatched main class of module " + mn + ": " + cn + " expected: " + mainClass); + } + } +} diff --git a/test/jdk/java/util/zip/ZipFile/Available.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java similarity index 64% rename from test/jdk/java/util/zip/ZipFile/Available.java rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java index 364a3b02439..99107602506 100644 --- a/test/jdk/java/util/zip/ZipFile/Available.java +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,17 +21,7 @@ * questions. */ -import java.util.zip.*; -import java.io.File; - -public class Available -{ - public static void main (String argv[]) throws Exception { - ZipFile zf = new ZipFile(new File(System.getProperty("test.src"), - "input.jar")); - ZipEntry e = zf.getEntry("ReleaseInflater.java"); - if (e.getSize() != zf.getInputStream(e).available()) { - throw new Exception("wrong return value of available"); - } - } +module com.foo { + requires jdk.httpserver; + requires net.foo; } diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java similarity index 61% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java index eeee969a252..360a989d9b3 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,21 +19,8 @@ * 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.stress.gclocker; - -/* - * @test TestGCLockerWithParallel - * @library / - * @requires vm.gc.Parallel - * @summary Stress Parallel's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseParallelGC gc.stress.gclocker.TestGCLockerWithParallel - */ -public class TestGCLockerWithParallel { - public static void main(String[] args) { - String[] testArgs = {"2", "PS Old Gen"}; - TestGCLocker.main(testArgs); - } +module net.foo { + requires jdk.jfr; } diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java new file mode 100644 index 00000000000..c147923e75a --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package net.foo; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.stream.Stream; + +/** + * Sanity test if SystemModules pre-resolved at link-time for net.foo + * with main class is loaded properly. + */ +public class Main { + public static void main(String... args) throws Exception { + ModuleDescriptor md = Main.class.getModule().getDescriptor(); + System.out.println(md); + + checkMainClass("com.foo", "com.foo.Main"); + checkMainClass("net.foo", "net.foo.Main"); + Stream.of("jdk.httpserver", "jdk.jfr").forEach(mn -> + ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass() + .orElseThrow(() -> new RuntimeException(mn + " no main class")) + ); + } + + static void checkMainClass(String mn, String mainClass) { + String cn = ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass().get(); + if (!cn.equals(mainClass)) { + throw new RuntimeException("Mismatched main class of module " + mn + ": " + cn + " expected: " + mainClass); + } + } + +} diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index ebf6a84e7b7..d747555a6bf 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -73,8 +73,6 @@ tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java 8057687 generic-all emit correct byte code an attributes for type annotations tools/javac/warnings/suppress/TypeAnnotations.java 8057683 generic-all improve ordering of errors with type annotations tools/javac/modules/SourceInSymlinkTest.java 8180263 windows-all fails when run on a subst drive -tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java 8312534 linux-i586 fails with assert "g1ConcurrentMark.cpp: Overflow during reference processing" -tools/javac/varargs/warning/Warn5.java 8312534 linux-i586 fails with assert "g1ConcurrentMark.cpp: Overflow during reference processing" ########################################################################### # diff --git a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java index 48106face35..d8539b8c656 100644 --- a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java +++ b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/jdk.internal.shellsupport.doc * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask - * @run testng/timeout=900/othervm JavadocHelperTest + * @run testng/timeout=900/othervm -Xmx1024m JavadocHelperTest */ import java.io.IOException; diff --git a/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java b/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java index 0f03248d733..f210b940b60 100644 --- a/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java +++ b/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java @@ -50,8 +50,12 @@ public class TestDocletExample extends TestRunner { public static void main(String... args) throws Exception { - var t = new TestDocletExample(); - t.runTests(m -> new Object[] { Path.of(m.getName()) }); + try { + var t = new TestDocletExample(); + t.runTests(m -> new Object[] { Path.of(m.getName()) }); + } catch (SnippetUtils.ConfigurationException e) { + System.err.println("NOTE: " + e.getMessage() + "; test skipped"); + } } SnippetUtils snippets; diff --git a/test/langtools/jdk/javadoc/doclet/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java b/test/langtools/jdk/javadoc/doclet/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java index 2931ae40f9d..3e5d978cc8f 100644 --- a/test/langtools/jdk/javadoc/doclet/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java +++ b/test/langtools/jdk/javadoc/doclet/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,13 +31,15 @@ * @run main TestMethodCommentsAlgorithm */ +import java.io.IOError; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.lang.model.element.Modifier; import javax.lang.model.type.TypeKind; @@ -109,6 +111,12 @@ * 3. While documentation for java.lang.Object is currently inaccessible outside * of the JDK, these test mimic what happens when the JDK documentation is * built. + * + * Note + * ==== + * + * If any of these tests cannot find a valid Object.java file in the test + * environment, they will throw jtreg.SkippedException. */ public class TestMethodCommentsAlgorithm extends JavadocTester { @@ -136,20 +144,7 @@ public static void main(String... args) throws Exception { */ @Test public void testMixedHierarchyEquals(Path base) throws Exception { - Path p = Path.of(System.getProperty("test.src", ".")).toAbsolutePath(); - while (!Files.exists(p.resolve("TEST.ROOT"))) { - p = p.getParent(); - if (p == null) { - throw new SkippedException("can't find TEST.ROOT"); - } - } - out.println("Test suite root: " + p); - Path javaBase = p.resolve("../../src/java.base").normalize(); - if (!Files.exists(javaBase)) { - throw new SkippedException("can't find java.base"); - } - out.println("java.base: " + javaBase); - + var javaBase = findJavaBase(); for (int i = 1; i < 7; i++) { mixedHierarchyI(base, javaBase, i); new OutputChecker("mymodule/x/T1.html").check(""" @@ -265,20 +260,7 @@ private static String generateDocComment(int index, int run, boolean includeComm */ @Test public void testInterfaceHierarchy(Path base) throws Exception { - Path p = Path.of(System.getProperty("test.src", ".")).toAbsolutePath(); - while (!Files.exists(p.resolve("TEST.ROOT"))) { - p = p.getParent(); - if (p == null) { - throw new SkippedException("can't find TEST.ROOT"); - } - } - System.err.println("Test suite root: " + p); - Path javaBase = p.resolve("../../src/java.base").normalize(); - if (!Files.exists(javaBase)) { - throw new SkippedException("can't find java.base"); - } - System.err.println("java.base: " + javaBase); - + var javaBase = findJavaBase(); for (int i = 1; i < 6; i++) { interfaceHierarchyI(base, javaBase, i); new OutputChecker("mymodule/x/T1.html").check(""" @@ -306,20 +288,7 @@ public void testInterfaceHierarchy(Path base) throws Exception { */ @Test public void testRecursiveInheritDocTagsAreProcessedFirst(Path base) throws Exception { - Path p = Path.of(System.getProperty("test.src", ".")).toAbsolutePath(); - while (!Files.exists(p.resolve("TEST.ROOT"))) { - p = p.getParent(); - if (p == null) { - throw new SkippedException("can't find TEST.ROOT"); - } - } - System.err.println("Test suite root: " + p); - Path javaBase = p.resolve("../../src/java.base").normalize(); - if (!Files.exists(javaBase)) { - throw new SkippedException("can't find java.base"); - } - System.err.println("java.base: " + javaBase); - + var javaBase = findJavaBase(); Path src = base.resolve("src"); tb.writeJavaFiles(src.resolve("mymodule"), """ package x; @@ -418,41 +387,67 @@ public interface T5 { } /* - * Takes a path to the java.base module, finds the Object.java file in - * there, creates a copy of that file _with the modified doc comment_ - * for Object.equals in the provided destination directory and returns - * the path to that created copy. + * Locates source of the java.base module. */ - private Path createPatchedJavaLangObject(Path src, Path dst, String newComment) - throws IOException { - if (!Files.isDirectory(src) || !Files.isDirectory(dst)) { - throw new IllegalArgumentException(); + private Path findJavaBase() { + String testSrc = System.getProperty("test.src"); + if (testSrc == null) { + // shouldn't happen + throw new SkippedException("test.src is not set"); } - var obj = Path.of("java/lang/Object.java"); - List files; - // ensure Object.java is found and unique - try (var s = Files.find(src, Integer.MAX_VALUE, - (p, attr) -> attr.isRegularFile() && p.endsWith(obj))) { - files = s.limit(2).toList(); // 2 is enough to deduce non-uniqueness + Path start; + try { + start = Path.of(testSrc).toAbsolutePath(); + } catch (InvalidPathException | IOError e) { + throw new SkippedException("Couldn't make sense of '" + testSrc + "'", e); } - if (files.size() != 1) { - throw new IllegalStateException(Arrays.toString(files.toArray())); + Path p = start; + while (!Files.exists(p.resolve("TEST.ROOT"))) { + p = p.getParent(); + if (p == null) { + // shouldn't happen as jtreg won't even run a test without TEST.ROOT + throw new SkippedException("Couldn't find TEST.ROOT above '" + start + "'"); + } } - var original = files.get(0); - out.println("found " + original.toAbsolutePath()); - var source = Files.readString(original); - var region = findDocCommentRegion(original); - var newSource = source.substring(0, region.start) - + newComment - + source.substring(region.end); - // create intermediate directories in the destination first, otherwise - // writeString will throw java.nio.file.NoSuchFileException - var copy = dst.resolve(src.relativize(original)); - out.println("to be copied to " + copy); - if (Files.notExists(copy.getParent())) { - Files.createDirectories(copy.getParent()); + Path javaBase = p.resolve("../../src/java.base").normalize(); + out.println("Source for java.base is found at: " + javaBase); + return javaBase; + } + + /* + * Finds java/lang/Object.java rooted at src, creates a copy of that file + * _with the modified doc comment_ for Object.equals in dst, and returns + * the path to that copy. + */ + private Path createPatchedJavaLangObject(Path src, Path dst, String newComment) { + var obj = Path.of("java/lang/Object.java"); + try { + Optional files; + try (var s = Files.find(src, Integer.MAX_VALUE, + (p, attr) -> attr.isRegularFile() && p.endsWith(obj))) { + files = s.findAny(); + } + if (files.isEmpty()) { + throw new SkippedException("Couldn't find '" + obj + "' at '" + src + "'"); + } + var original = files.get(); + out.println("Found '" + obj + "' at " + original.toAbsolutePath()); + var source = Files.readString(original); + var region = findDocCommentRegion(original); + var newSource = source.substring(0, region.start) + + newComment + + source.substring(region.end); + // create intermediate directories in the destination first, otherwise + // writeString will throw java.nio.file.NoSuchFileException + var copy = dst.resolve(src.relativize(original)); + out.println("To be copied to '" + copy + "'"); + if (Files.notExists(copy.getParent())) { + Files.createDirectories(copy.getParent()); + } + return Files.writeString(copy, newSource, StandardOpenOption.CREATE); + } catch (IOException e) { + throw new SkippedException("Couldn't create patched '" + obj + "'", e); } - return Files.writeString(copy, newSource, StandardOpenOption.CREATE); } private static SourceRegion findDocCommentRegion(Path src) throws IOException { @@ -464,14 +459,18 @@ private static SourceRegion findDocCommentRegion(Path src) throws IOException { var task = (JavacTask) compiler.getTask(null, null, null, null, null, List.of(fileObject)); Iterator iterator = task.parse().iterator(); if (!iterator.hasNext()) { - throw new AssertionError(); + throw new SkippedException("Couldn't parse '" + src + "'"); } var tree = iterator.next(); var pathToEqualsMethod = findMethod(tree); + if (pathToEqualsMethod == null) { + throw new SkippedException("Couldn't find the equals method in '" + src + "'"); + } var trees = DocTrees.instance(task); DocCommentTree docCommentTree = trees.getDocCommentTree(pathToEqualsMethod); - if (docCommentTree == null) - throw new AssertionError("cannot find the doc comment for java.lang.Object#equals"); + if (docCommentTree == null) { + throw new SkippedException("Couldn't find documentation for the equals method at '" + src + "'"); + } var positions = trees.getSourcePositions(); long start = positions.getStartPosition(null, docCommentTree, docCommentTree); long end = positions.getEndPosition(null, docCommentTree, docCommentTree); @@ -510,7 +509,7 @@ public Void visitMethod(MethodTree m, Void unused) { List params = m.getParameters(); if (params.size() != 1) return null; - var parameterType = params.get(0).getType(); + var parameterType = params.getFirst().getType(); if (parameterType.getKind() == Tree.Kind.IDENTIFIER && ((IdentifierTree) parameterType).getName().toString().equals("Object")) { throw new Result(getCurrentPath()); diff --git a/test/langtools/jdk/javadoc/tool/BadOptionsTest.java b/test/langtools/jdk/javadoc/tool/BadOptionsTest.java index e0887ed5646..568b6de9055 100644 --- a/test/langtools/jdk/javadoc/tool/BadOptionsTest.java +++ b/test/langtools/jdk/javadoc/tool/BadOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8169676 8175055 + * @bug 8169676 8175055 8323016 * @summary boolean result of Option.process is often ignored * @modules jdk.compiler/com.sun.tools.javac.api * @modules jdk.compiler/com.sun.tools.javac.main @@ -151,6 +151,75 @@ public void testSourcePathAndModuleSourceConflict() throws IOException { "1 error"); } + @Test + public void testOptionNotFound_NoSuggestions() { + var result = new JavadocTask(tb, Task.Mode.CMDLINE) + .options("--not-a-path") + .run(Task.Expect.FAIL) + .writeAll(); + checkFound(String.join("\n", result.getOutputLines(Task.OutputKind.DIRECT)), + """ + error: invalid flag: --not-a-path + For more details on available options, use --help or --help-extra""" + ); + } + + @Test + public void testOptionNotFound_OneSuggestion() { + var result = new JavadocTask(tb, Task.Mode.CMDLINE) + .options("--middle-path") + .run(Task.Expect.FAIL) + .writeAll(); + checkFound(String.join("\n", result.getOutputLines(Task.OutputKind.DIRECT)), + """ + error: invalid flag: --middle-path + Did you mean: --module-path + For more details on available options, use --help or --help-extra""" + ); + } + + @Test + public void testOptionNotFound_TwoSuggestions() { + var result = new JavadocTask(tb, Task.Mode.CMDLINE) + .options("--sourcepath") + .run(Task.Expect.FAIL) + .writeAll(); + checkFound(String.join("\n", result.getOutputLines(Task.OutputKind.DIRECT)), + """ + error: invalid flag: --sourcepath + Did you mean one of: --source-path -sourcepath + For more details on available options, use --help or --help-extra""" + ); + } + + @Test + public void testOptionNotFound_ThreeSuggestions() { + var result = new JavadocTask(tb, Task.Mode.CMDLINE) + .options("--classpath") + .run(Task.Expect.FAIL) + .writeAll(); + checkFound(String.join("\n", result.getOutputLines(Task.OutputKind.DIRECT)), + """ + error: invalid flag: --classpath + Did you mean one of: --class-path -classpath -bootclasspath + For more details on available options, use --help or --help-extra""" + ); + } + + @Test + public void testOptionNotFound_DocletOption() { + var result = new JavadocTask(tb, Task.Mode.CMDLINE) + .options("-tiglet") + .run(Task.Expect.FAIL) + .writeAll(); + checkFound(String.join("\n", result.getOutputLines(Task.OutputKind.DIRECT)), + """ + error: invalid flag: -tiglet + Did you mean: -taglet + For more details on available options, use --help or --help-extra""" + ); + } + private void checkFound(String log, String... expect) { for (String e : expect) { if (!log.contains(e)) { diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 51ccbd17d60..98a543e77a9 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8144903 8177466 8191842 8211694 8213725 8239536 8257236 8252409 8294431 + * @bug 8144903 8177466 8191842 8211694 8213725 8239536 8257236 8252409 8294431 8322003 8322532 * @summary Tests for EvaluationState.variables * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -621,4 +621,21 @@ public void varAnonymousClassAndStaticField() { //JDK-8294431 assertEval("var obj = new Object() { public static final String msg = \"hello\"; };"); } + public void underscoreAsLambdaParameter() { //JDK-8322532 + assertAnalyze("Func f = _ -> 0; int i;", + "Func f = _ -> 0;", + " int i;", true); + } + + public void intersectionTypeAsTypeArgument() { //JDK-8322003 + assertEval("interface Shape {}"); + assertEval("record Square(int edge) implements Shape {}"); + assertEval("record Circle(int radius) implements Shape {}"); + assertEval("java.util.function.Consumer printShape = System.out::println;"); + assertEval("Square square = new Square(1);"); + assertEval("Circle circle = new Circle(1);"); + assertEval("var shapes = java.util.List.of(square, circle);"); + assertEval("shapes.forEach(printShape);"); + } + } diff --git a/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java b/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java index 10030df1679..eb5b071df6f 100644 --- a/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java +++ b/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java @@ -58,7 +58,11 @@ */ public class TestJavaxToolsSnippets extends TestRunner { public static void main(String... args) throws Exception { - new TestJavaxToolsSnippets().runTests(m -> new Object[] { Path.of(m.getName()) }); + try { + new TestJavaxToolsSnippets().runTests(m -> new Object[] { Path.of(m.getName()) }); + } catch (SnippetUtils.ConfigurationException e) { + System.err.println("NOTE: " + e.getMessage() + "; test skipped"); + } } SnippetUtils snippets = new SnippetUtils("java.compiler"); diff --git a/test/langtools/tools/javac/classreader/BadMethodParameter.java b/test/langtools/tools/javac/classreader/BadMethodParameter.java new file mode 100644 index 00000000000..b37a196e2ed --- /dev/null +++ b/test/langtools/tools/javac/classreader/BadMethodParameter.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2023, Alphabet LLC. All rights reserved. + * 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 8322040 + * @summary Missing array bounds check in ClassReader.parameter + * @library /tools/lib /tools/javac/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @enablePreview + * @run main BadMethodParameter + */ + +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.attribute.MethodParametersAttribute; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; + +public class BadMethodParameter extends TestRunner { + + protected ToolBox tb; + + BadMethodParameter() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new BadMethodParameter().runTests(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] {Paths.get(m.getName())}); + } + + @Test + public void testAnnoOnConstructors(Path base) throws Exception { + Path src = base.resolve("src"); + Path t = src.resolve("T.java"); + Path classes = base.resolve("classes"); + + Files.createDirectories(classes); + + tb.writeJavaFiles( + src, + """ + class T { + public static void f(int x, int y) { + } + } + """); + + new JavacTask(tb).options("-parameters").files(t).outdir(classes).run(); + + transform(classes.resolve("T.class")); + + Path classDir = getClassDir(); + new JavacTask(tb) + .classpath(classes, classDir) + .options("--enable-preview", + "-source", String.valueOf(Runtime.version().feature()), + "-verbose", "-parameters", "-processor", P.class.getName()) + .classes(P.class.getName()) + .outdir(classes) + .run(Task.Expect.SUCCESS); + } + + public Path getClassDir() { + String classes = ToolBox.testClasses; + if (classes == null) { + return Paths.get("build"); + } else { + return Paths.get(classes); + } + } + + @SupportedAnnotationTypes("*") + public static final class P extends AbstractProcessor { + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (processingEnv.getElementUtils().getTypeElement("T") == null) { + throw new AssertionError("could not load T"); + } + return false; + } + } + + private static void transform(Path path) throws IOException { + byte[] bytes = Files.readAllBytes(path); + ClassFile cf = ClassFile.of(); + ClassModel classModel = cf.parse(bytes); + MethodTransform methodTransform = + (mb, me) -> { + if (me instanceof MethodParametersAttribute mp) { + // create a MethodParameters attribute with the wrong number of entries + mb.with( + MethodParametersAttribute.of( + mp.parameters().subList(0, mp.parameters().size() - 1))); + } else { + mb.with(me); + } + }; + + ClassTransform classTransform = ClassTransform.transformingMethods(methodTransform); + bytes = cf.transform(classModel, classTransform); + Files.write(path, bytes); + } +} diff --git a/test/langtools/tools/javac/launcher/GetResourceTest.java b/test/langtools/tools/javac/launcher/GetResourceTest.java index 095a43f39f1..4b46cb034ee 100644 --- a/test/langtools/tools/javac/launcher/GetResourceTest.java +++ b/test/langtools/tools/javac/launcher/GetResourceTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8210009 + * @bug 8210009 8321739 * @summary Source Launcher classloader should support getResource and getResourceAsStream * @enablePreview * @modules jdk.compiler @@ -41,7 +41,7 @@ /* * The body of this test is in ${test.src}/src/p/q/CLTest.java, - * which is executed in single-file source-launcher mode, + * which is executed in source-launcher mode, * in order to test the classloader used to launch such programs. */ public class GetResourceTest { diff --git a/test/langtools/tools/javac/launcher/src/java b/test/langtools/tools/javac/launcher/src/java new file mode 100644 index 00000000000..b1478523807 --- /dev/null +++ b/test/langtools/tools/javac/launcher/src/java @@ -0,0 +1 @@ +A text file named `java` to simulate https://bugs.openjdk.org/browse/JDK-8321739 diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 607575b291f..2ab92a625d0 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 + * @bug 8301580 8322159 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @enablePreview @@ -87,4 +87,41 @@ class C { } } + @Test + public void testX() throws Exception { + String code = """ + public class C { + public C() { + Undefined.method(); + undefined1(); + Runnable r = this::undefined2; + overridable(this); //to verify ThisEscapeAnalyzer has been run + } + public void overridable(C c) {} + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", + "-XDshould-stop.at=FLOW", "-Xlint:this-escape") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:3:9: compiler.err.cant.resolve.location: kindname.variable, Undefined, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:4:9: compiler.err.cant.resolve.location.args: kindname.method, undefined1, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:5:22: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, undefined2, , , (compiler.misc.location: kindname.class, C, null))", + "C.java:6:20: compiler.warn.possible.this.escape", + "3 errors", + "1 warning" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } diff --git a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java index 0b20fee0b81..16860d65cc2 100644 --- a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java +++ b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java @@ -142,7 +142,6 @@ private void checkSealedClassFile(Path out, String cfName, List expected } catch (ConstantPoolException ex) { } }); - subtypeNames.sort((s1, s2) -> s1.compareTo(s2)); for (int i = 0; i < expectedSubTypeNames.size(); i++) { Assert.check(expectedSubTypeNames.get(0).equals(subtypeNames.get(0))); } @@ -695,4 +694,38 @@ public void testSupertypePermitsLoop(Path base) throws Exception { .run() .writeAll(); } + + @Test + public void testClientSwapsPermittedSubclassesOrder(Path base) throws Exception { + Path src = base.resolve("src"); + Path foo = src.resolve("Foo.java"); + Path fooUser = src.resolve("FooUser.java"); + + tb.writeFile(foo, + """ + public sealed interface Foo { + record R1() implements Foo {} + record R2() implements Foo {} + } + """); + + tb.writeFile(fooUser, + """ + public class FooUser { + // see that the order of arguments differ from the order of subclasses of Foo in the source above + // we need to check that the order of permitted subclasses of Foo in the class file corresponds to the + // original order in the source code + public void blah(Foo.R2 a, Foo.R1 b) {} + } + """); + + Path out = base.resolve("out"); + Files.createDirectories(out); + + new JavacTask(tb) + .outdir(out) + .files(fooUser, foo) + .run(); + checkSealedClassFile(out, "Foo.class", List.of("Foo$R1", "Foo$R2")); + } } diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java index b5c94d3ce94..1c040052e69 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java @@ -1,12 +1,12 @@ /* * @test /nodynamiccopyright/ - * @bug 8206986 8222169 8224031 8240964 8267119 8268670 + * @bug 8206986 8222169 8224031 8240964 8267119 8268670 8321582 * @summary Check expression switch works. - * @compile/fail/ref=ExpressionSwitch-old.out --release 9 -XDrawDiagnostics ExpressionSwitch.java * @compile ExpressionSwitch.java * @run main ExpressionSwitch */ +// * @compile/fail/ref=ExpressionSwitch-old.out --release 9 -XDrawDiagnostics ExpressionSwitch.java import java.util.Objects; import java.util.function.Supplier; @@ -35,6 +35,16 @@ private void run() { localClass(T.A); assertEquals(castSwitchExpressions(T.A), "A"); testTypeInference(true, 0); + assertEquals(yieldPrimitiveDotClass("byte"), byte.class); + assertEquals(yieldPrimitiveDotClass("char"), char.class); + assertEquals(yieldPrimitiveDotClass("short"), short.class); + assertEquals(yieldPrimitiveDotClass("int"), int.class); + assertEquals(yieldPrimitiveDotClass("long"), long.class); + assertEquals(yieldPrimitiveDotClass("float"), float.class); + assertEquals(yieldPrimitiveDotClass("double"), double.class); + assertEquals(yieldPrimitiveDotClass("void"), void.class); + assertEquals(yieldPrimitiveDotClass("boolean"), boolean.class); + assertEquals(yieldPrimitiveDotClass("other"), null); } private String print(T t) { @@ -140,6 +150,21 @@ private boolean yieldUnaryNotOperator(String s, boolean b) { }; } + private Class yieldPrimitiveDotClass(String s) { + return switch (s) { + case "byte": yield byte.class; + case "char": yield char.class; + case "short": yield short.class; + case "int": yield int.class; + case "long": yield long.class; + case "float": yield float.class; + case "double": yield double.class; + case "void": yield void.class; + case "boolean": yield boolean.class; + default: yield null; + }; + } + private void localClass(T t) { String good = "good"; class L { diff --git a/test/lib-test/jdk/test/lib/RandomGeneratorTest.java b/test/lib-test/jdk/test/lib/RandomGeneratorTest.java index ce57ebfe65f..71e36bdc9c4 100644 --- a/test/lib-test/jdk/test/lib/RandomGeneratorTest.java +++ b/test/lib-test/jdk/test/lib/RandomGeneratorTest.java @@ -69,7 +69,7 @@ public static void main( String[] args) throws Throwable { jvmArgs.add(origFileName); int fileNameIndex = jvmArgs.size() - 1; String[] cmdLineArgs = jvmArgs.toArray(new String[jvmArgs.size()]); - ProcessTools.executeTestJvm(cmdLineArgs).shouldHaveExitValue(0); + ProcessTools.executeTestJava(cmdLineArgs).shouldHaveExitValue(0); String etalon = Utils.fileAsString(origFileName).trim(); cmdLineArgs[fileNameIndex] = seedOpt.name(); seedOpt.verify(etalon, cmdLineArgs); @@ -143,7 +143,7 @@ public void verify(String orig, String[] cmdLine) { String output; OutputAnalyzer oa; try { - oa = ProcessTools.executeTestJvm(cmdLine); + oa = ProcessTools.executeTestJava(cmdLine); } catch (Throwable t) { throw new Error("TESTBUG: Unexpedted exception during jvm execution.", t); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java b/test/lib-test/jdk/test/lib/process/ProcessToolsExecuteLimitedTestJavaTest.java similarity index 54% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java rename to test/lib-test/jdk/test/lib/process/ProcessToolsExecuteLimitedTestJavaTest.java index 76b096a3f3d..4331f9ab374 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java +++ b/test/lib-test/jdk/test/lib/process/ProcessToolsExecuteLimitedTestJavaTest.java @@ -21,30 +21,25 @@ * questions. */ -package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; - -import compiler.lib.ir_framework.TestFramework; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * This class keeps track of all {@link WriterThread} instances. +/* + * @test + * @summary Unit test for ProcessTools.executeLimitedTestJava() + * @library /test/lib + * @run main/othervm -Dtest.java.opts=-XX:MaxMetaspaceSize=123456789 ProcessToolsExecuteLimitedTestJavaTest */ -class WriterThreads { - private final Map mapIdToThread = new HashMap<>(); - WriterThread parse(String line) { - int writerThreadId = parseWriterThreadId(line); - return mapIdToThread.computeIfAbsent(writerThreadId, c -> new WriterThread()); - } +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; - private static int parseWriterThreadId(String line) { - Pattern pattern = Pattern.compile("='(\\d+)'"); - Matcher matcher = pattern.matcher(line); - TestFramework.check(matcher.find(), "should find writer thread id"); - return Integer.parseInt(matcher.group(1)); +public class ProcessToolsExecuteLimitedTestJavaTest { + public static void main(String[] args) throws Exception { + if (args.length > 0) { + // Do nothing. Just let the JVM log its output. + } else { + // In comparison to executeTestJava, executeLimitedTestJava should not add the + // -Dtest.java.opts flags. Check that it doesn't. + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+PrintFlagsFinal", "-version"); + output.stdoutShouldNotMatch(".*MaxMetaspaceSize.* = 123456789.*"); + } } } diff --git a/test/lib/jdk/test/lib/hprof/model/JavaClass.java b/test/lib/jdk/test/lib/hprof/model/JavaClass.java index 8209f6cf68c..827402cebc8 100644 --- a/test/lib/jdk/test/lib/hprof/model/JavaClass.java +++ b/test/lib/jdk/test/lib/hprof/model/JavaClass.java @@ -430,11 +430,6 @@ public int getInlinedInstanceSize() { } else { char sig = f.getSignature().charAt(0); switch (sig) { - case 'Q': { - System.out.println("WARNING: (getInlinedInstanceSize) field " - + getClazz().getName() + "." + f.getName() - + " is not inlined, but has Q-signature: " + f.getSignature()); - } // continue as 'L' object case 'L': case '[': size += mySnapshot.getIdentifierSize(); diff --git a/test/lib/jdk/test/lib/hprof/model/JavaObject.java b/test/lib/jdk/test/lib/hprof/model/JavaObject.java index bf54cdf86b1..18a2a66d385 100644 --- a/test/lib/jdk/test/lib/hprof/model/JavaObject.java +++ b/test/lib/jdk/test/lib/hprof/model/JavaObject.java @@ -266,10 +266,6 @@ private JavaThing[] parseFields(boolean verbose) { offset += fieldClass.getInlinedInstanceSize(); } else { switch (sig) { - case 'Q': { - warn("(parseFields) field " + getClazz().getName() + "." + f.getName() - + " is not inlined, but has Q-signature: " + f.getSignature()); - } // continue as 'L' object case 'L': case '[': { long id = objectIdAt(offset); diff --git a/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java b/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java index 3fc1d0e023f..ac3d3526fe2 100644 --- a/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java +++ b/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java @@ -358,10 +358,6 @@ public String valueString(boolean bigLimit) { result.append(val); break; } - case 'Q': { - InlinedJavaObject obj = (InlinedJavaObject)things[i]; - result.append(obj); - } default: { throw new RuntimeException("unknown primitive type?"); } diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java index ae04d9d1bc4..48a0b098d48 100644 --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java @@ -42,6 +42,8 @@ public final class OutputAnalyzer { private static final String deprecatedmsg = ".* VM warning:.* deprecated.*"; + private static final String FATAL_ERROR_PAT = "# A fatal error has been detected.*"; + private final OutputBuffer buffer; /** * Create an OutputAnalyzer, a utility class for verifying output and exit @@ -106,6 +108,14 @@ public OutputAnalyzer(String stdout, String stderr, int exitValue) buffer = OutputBuffer.of(stdout, stderr, exitValue); } + /** + * Delegate waitFor to the OutputBuffer. This ensures that + * the progress and timestamps are logged correctly. + */ + public void waitFor() { + buffer.waitFor(); + } + /** * Verify that the stdout contents of output buffer is empty * @@ -862,4 +872,11 @@ public void shouldContainMultiLinePattern(String... needles) { shouldContainMultiLinePattern(needles, true); } + /** + * Assert that we did not crash with a hard VM error (generating an hs_err_pidXXX.log) + */ + public void shouldNotHaveFatalError() { + shouldNotMatch(FATAL_ERROR_PAT); + } + } diff --git a/test/lib/jdk/test/lib/process/OutputBuffer.java b/test/lib/jdk/test/lib/process/OutputBuffer.java index fba2a5f6dcf..f032591f358 100644 --- a/test/lib/jdk/test/lib/process/OutputBuffer.java +++ b/test/lib/jdk/test/lib/process/OutputBuffer.java @@ -44,6 +44,12 @@ public OutputBufferException(Throwable cause) { } } + /** + * Waits for a process to finish, if there is one assocated with + * this OutputBuffer. + */ + public void waitFor(); + /** * Returns the stdout result * @@ -67,6 +73,13 @@ default public List getStdoutAsList() { * @return stderr result */ public String getStderr(); + + + /** + * Returns the exit value + * + * @return exit value + */ public int getExitValue(); /** @@ -136,20 +149,12 @@ private LazyOutputBuffer(Process p, Charset cs) { } @Override - public String getStdout() { - return outTask.get(); - } - - @Override - public String getStderr() { - return errTask.get(); - } - - @Override - public int getExitValue() { + public void waitFor() { if (exitValue != null) { - return exitValue; + // Already waited for this process + return; } + try { logProgress("Waiting for completion"); boolean aborted = true; @@ -157,7 +162,6 @@ public int getExitValue() { exitValue = p.waitFor(); logProgress("Waiting for completion finished"); aborted = false; - return exitValue; } finally { if (aborted) { logProgress("Waiting for completion FAILED"); @@ -169,6 +173,22 @@ public int getExitValue() { } } + @Override + public String getStdout() { + return outTask.get(); + } + + @Override + public String getStderr() { + return errTask.get(); + } + + @Override + public int getExitValue() { + waitFor(); + return exitValue; + } + @Override public long pid() { return p.pid(); @@ -186,6 +206,11 @@ private EagerOutputBuffer(String stdout, String stderr, int exitValue) { this.exitValue = exitValue; } + @Override + public void waitFor() { + // Nothing to do since this buffer is not associated with a Process. + } + @Override public String getStdout() { return stdout; diff --git a/test/lib/jdk/test/lib/process/ProcessTools.java b/test/lib/jdk/test/lib/process/ProcessTools.java index db80a439f2b..aafb6fe3f4c 100644 --- a/test/lib/jdk/test/lib/process/ProcessTools.java +++ b/test/lib/jdk/test/lib/process/ProcessTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -608,43 +608,69 @@ public static ProcessBuilder createLimitedTestJavaProcessBuilder(String... comma } /** - * Executes a test jvm process, waits for it to finish and returns + * Executes a process using the java launcher from the jdk to + * be tested, waits for it to finish and returns * the process output. * *

    The process is created using runtime flags set up by: * {@link #createTestJavaProcessBuilder(String...)}. The * jvm process will have exited before this method returns. * - * @param cmds User specified arguments. + * @param command User specified arguments. * @return The output from the process. */ - public static OutputAnalyzer executeTestJvm(List cmds) throws Exception { - return executeTestJvm(cmds.toArray(String[]::new)); + public static OutputAnalyzer executeTestJava(List command) throws Exception { + return executeTestJava(command.toArray(String[]::new)); } /** - * Executes a test jvm process, waits for it to finish and returns + * Executes a process using the java launcher from the jdk to + * be tested, waits for it to finish and returns * the process output. * *

    The process is created using runtime flags set up by: * {@link #createTestJavaProcessBuilder(String...)}. The * jvm process will have exited before this method returns. * - * @param cmds User specified arguments. + * @param command User specified arguments. * @return The output from the process. */ - public static OutputAnalyzer executeTestJvm(String... cmds) throws Exception { - ProcessBuilder pb = createTestJavaProcessBuilder(cmds); + public static OutputAnalyzer executeTestJava(String... command) throws Exception { + ProcessBuilder pb = createTestJavaProcessBuilder(command); return executeProcess(pb); } /** - * @param cmds User specified arguments. + * Executes a process using the java launcher from the jdk to + * be tested, waits for it to finish and returns + * the process output. + * + *

    The process is created using runtime flags set up by: + * {@link #createLimitedTestJavaProcessBuilder(String...)}. The + * jvm process will have exited before this method returns. + * + * @param command User specified arguments. * @return The output from the process. - * @see #executeTestJvm(String...) */ - public static OutputAnalyzer executeTestJava(String... cmds) throws Exception { - return executeTestJvm(cmds); + public static OutputAnalyzer executeLimitedTestJava(List command) throws Exception { + return executeLimitedTestJava(command.toArray(String[]::new)); + } + + /** + * Executes a process using the java launcher from the jdk to + * be tested, waits for it to finish and returns + * the process output. + * + *

    The process is created using runtime flags set up by: + * {@link #createLimitedTestJavaProcessBuilder(String...)}. The + * jvm process will have exited before this method returns. + * + * @param command User specified arguments. + * @return The output from the process. + */ + public static OutputAnalyzer executeLimitedTestJava(String... command) throws Exception { + ProcessBuilder pb = createLimitedTestJavaProcessBuilder(command); + return executeProcess(pb); } /** @@ -697,7 +723,10 @@ public static OutputAnalyzer executeProcess(ProcessBuilder pb, String input, } output = new OutputAnalyzer(p, cs); - p.waitFor(); + + // Wait for the process to finish. Call through the output + // analyzer to get correct logging and timestamps. + output.waitFor(); { // Dumping the process output to a separate file var fileName = String.format("pid-%d-output.log", p.pid()); @@ -735,7 +764,7 @@ public static OutputAnalyzer executeProcess(ProcessBuilder pb, String input, * @param cmds The command line to execute. * @return The output from the process. */ - public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { + public static OutputAnalyzer executeProcess(String... cmds) throws Exception { return executeProcess(new ProcessBuilder(cmds)); } @@ -780,8 +809,7 @@ public static String getCommandLine(ProcessBuilder pb) { * @param cmds The command line to execute. * @return The {@linkplain OutputAnalyzer} instance wrapping the process. */ - public static OutputAnalyzer executeCommand(String... cmds) - throws Throwable { + public static OutputAnalyzer executeCommand(String... cmds) throws Exception { String cmdLine = String.join(" ", cmds); System.out.println("Command line: [" + cmdLine + "]"); OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds); @@ -798,8 +826,7 @@ public static OutputAnalyzer executeCommand(String... cmds) * @param pb The ProcessBuilder to execute. * @return The {@linkplain OutputAnalyzer} instance wrapping the process. */ - public static OutputAnalyzer executeCommand(ProcessBuilder pb) - throws Throwable { + public static OutputAnalyzer executeCommand(ProcessBuilder pb) throws Exception { String cmdLine = pb.command().stream() .map(x -> (x.contains(" ") || x.contains("$")) ? ("'" + x + "'") : x) diff --git a/test/lib/jdk/test/lib/security/TestCertificate.java b/test/lib/jdk/test/lib/security/TestCertificate.java index e5a2f5f42f2..8658a38e5b2 100644 --- a/test/lib/jdk/test/lib/security/TestCertificate.java +++ b/test/lib/jdk/test/lib/security/TestCertificate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ public enum TestCertificate { // Subject: CN=SSLCertificate, O=SomeCompany // Issuer: CN=Intermediate CA Cert, O=SomeCompany // Validity: Tue Aug 30 14:37:19 PDT 2016 to Wed Aug 30 14:37:19 PDT 2017 - ONE("1000", + ONE("10:00", "CN=SSLCertificate, O=SomeCompany", "CN=Intermediate CA Cert, O=SomeCompany", -1063259762, diff --git a/test/lib/jdk/test/lib/security/TestTLSHandshake.java b/test/lib/jdk/test/lib/security/TestTLSHandshake.java index ea5cadd6463..1b36f66f7e0 100644 --- a/test/lib/jdk/test/lib/security/TestTLSHandshake.java +++ b/test/lib/jdk/test/lib/security/TestTLSHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,8 @@ public final class TestTLSHandshake extends SSLSocketTest { "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; public static final long CERT_ID = Integer.toUnsignedLong(-1057291798); public static final long ANCHOR_CERT_ID = Integer.toUnsignedLong(1688661792); - public static final String CERT_SERIAL = "edbec8f705af2514"; - public static final String ANCHOR_CERT_SERIAL = "8e191778b2f331be"; + public static final String CERT_SERIAL = "00:ed:be:c8:f7:05:af:25:14"; + public static final String ANCHOR_CERT_SERIAL = "8e:19:17:78:b2:f3:31:be"; public String protocolVersion; public String peerHost; diff --git a/test/lib/jdk/test/lib/thread/VThreadPinner.java b/test/lib/jdk/test/lib/thread/VThreadPinner.java new file mode 100644 index 00000000000..25b06912fdf --- /dev/null +++ b/test/lib/jdk/test/lib/thread/VThreadPinner.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.thread; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.file.Path; +import java.time.Duration; +import java.util.concurrent.atomic.AtomicReference; +import jdk.test.lib.thread.VThreadRunner.ThrowingRunnable; + +/** + * Helper class to allow tests run a task in a virtual thread while pinning its carrier. + * + * It defines the {@code runPinned} method to run a task with a native frame on the stack. + */ +public class VThreadPinner { + private static final Path JAVA_LIBRARY_PATH = Path.of(System.getProperty("java.library.path")); + private static final Path LIB_PATH = JAVA_LIBRARY_PATH.resolve(System.mapLibraryName("VThreadPinner")); + + // method handle to call the native function + private static final MethodHandle INVOKER = invoker(); + + // function pointer to call + private static final MemorySegment UPCALL_STUB = upcallStub(); + + /** + * Thread local with the task to run. + */ + private static final ThreadLocal TASK_RUNNER = new ThreadLocal<>(); + + /** + * Runs a task, capturing any exception or error thrown. + */ + private static class TaskRunner implements Runnable { + private final ThrowingRunnable task; + private Throwable throwable; + + TaskRunner(ThrowingRunnable task) { + this.task = task; + } + + @Override + public void run() { + try { + task.run(); + } catch (Throwable ex) { + throwable = ex; + } + } + + Throwable exception() { + return throwable; + } + } + + /** + * Called by the native function to run the task stashed in the thread local. The + * task runs with the native frame on the stack. + */ + private static void callback() { + TASK_RUNNER.get().run(); + } + + /** + * Runs the given task on a virtual thread pinned to its carrier. If called from a + * virtual thread then it invokes the task directly. + */ + public static void runPinned(ThrowingRunnable task) throws X { + if (!Thread.currentThread().isVirtual()) { + VThreadRunner.run(() -> runPinned(task)); + return; + } + var runner = new TaskRunner(task); + TASK_RUNNER.set(runner); + try { + INVOKER.invoke(UPCALL_STUB); + } catch (Throwable e) { + throw new RuntimeException(e); + } finally { + TASK_RUNNER.remove(); + } + Throwable ex = runner.exception(); + if (ex != null) { + if (ex instanceof RuntimeException e) + throw e; + if (ex instanceof Error e) + throw e; + throw (X) ex; + } + } + + /** + * Returns a method handle to the native function void call(void *(*f)(void *)). + */ + @SuppressWarnings("restricted") + private static MethodHandle invoker() { + Linker abi = Linker.nativeLinker(); + try { + SymbolLookup lib = SymbolLookup.libraryLookup(LIB_PATH, Arena.global()); + MemorySegment symbol = lib.find("call").orElseThrow(); + FunctionDescriptor desc = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS); + return abi.downcallHandle(symbol, desc); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + /** + * Returns an upcall stub to use as a function pointer to invoke the callback method. + */ + @SuppressWarnings("restricted") + private static MemorySegment upcallStub() { + Linker abi = Linker.nativeLinker(); + try { + MethodHandle callback = MethodHandles.lookup() + .findStatic(VThreadPinner.class, "callback", MethodType.methodType(void.class)); + return abi.upcallStub(callback, FunctionDescriptor.ofVoid(), Arena.global()); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/test/lib/jdk/test/lib/thread/VThreadRunner.java b/test/lib/jdk/test/lib/thread/VThreadRunner.java index 74158c89a14..ba69496a047 100644 --- a/test/lib/jdk/test/lib/thread/VThreadRunner.java +++ b/test/lib/jdk/test/lib/thread/VThreadRunner.java @@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicReference; /** - * Helper class to support tests running tasks a in virtual thread. + * Helper class to support tests running tasks in a virtual thread. */ public class VThreadRunner { private VThreadRunner() { } @@ -41,38 +41,31 @@ private VThreadRunner() { } public static final int NO_INHERIT_THREAD_LOCALS = 1 << 2; /** - * Represents a task that does not return a result but may throw - * an exception. + * Represents a task that does not return a result but may throw an exception. */ @FunctionalInterface - public interface ThrowingRunnable { - /** - * Runs this operation. - */ - void run() throws Exception; + public interface ThrowingRunnable { + void run() throws X; } /** * Run a task in a virtual thread and wait for it to terminate. * If the task completes with an exception then it is thrown by this method. - * If the task throws an Error then it is wrapped in an RuntimeException. * * @param name thread name, can be null * @param characteristics thread characteristics * @param task the task to run - * @throws Exception the exception thrown by the task + * @throws X the exception thrown by the task */ - public static void run(String name, - int characteristics, - ThrowingRunnable task) throws Exception { - AtomicReference exc = new AtomicReference<>(); - Runnable target = () -> { + public static void run(String name, + int characteristics, + ThrowingRunnable task) throws X { + var throwableRef = new AtomicReference(); + Runnable target = () -> { try { task.run(); - } catch (Error e) { - exc.set(new RuntimeException(e)); - } catch (Exception e) { - exc.set(e); + } catch (Throwable ex) { + throwableRef.set(ex); } }; @@ -84,54 +77,59 @@ public static void run(String name, Thread thread = builder.start(target); // wait for thread to terminate - while (thread.join(Duration.ofSeconds(10)) == false) { - System.out.println("-- " + thread + " --"); - for (StackTraceElement e : thread.getStackTrace()) { - System.out.println(" " + e); + try { + while (thread.join(Duration.ofSeconds(10)) == false) { + System.out.println("-- " + thread + " --"); + for (StackTraceElement e : thread.getStackTrace()) { + System.out.println(" " + e); + } } + } catch (InterruptedException e) { + throw new RuntimeException(e); } - Exception e = exc.get(); - if (e != null) { - throw e; + Throwable ex = throwableRef.get(); + if (ex != null) { + if (ex instanceof RuntimeException e) + throw e; + if (ex instanceof Error e) + throw e; + throw (X) ex; } } /** * Run a task in a virtual thread and wait for it to terminate. * If the task completes with an exception then it is thrown by this method. - * If the task throws an Error then it is wrapped in an RuntimeException. * * @param name thread name, can be null * @param task the task to run - * @throws Exception the exception thrown by the task + * @throws X the exception thrown by the task */ - public static void run(String name, ThrowingRunnable task) throws Exception { + public static void run(String name, ThrowingRunnable task) throws X { run(name, 0, task); } /** * Run a task in a virtual thread and wait for it to terminate. * If the task completes with an exception then it is thrown by this method. - * If the task throws an Error then it is wrapped in an RuntimeException. * * @param characteristics thread characteristics * @param task the task to run - * @throws Exception the exception thrown by the task + * @throws X the exception thrown by the task */ - public static void run(int characteristics, ThrowingRunnable task) throws Exception { + public static void run(int characteristics, ThrowingRunnable task) throws X { run(null, characteristics, task); } /** * Run a task in a virtual thread and wait for it to terminate. * If the task completes with an exception then it is thrown by this method. - * If the task throws an Error then it is wrapped in an RuntimeException. * * @param task the task to run - * @throws Exception the exception thrown by the task + * @throws X the exception thrown by the task */ - public static void run(ThrowingRunnable task) throws Exception { + public static void run(ThrowingRunnable task) throws X { run(null, 0, task); } diff --git a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c b/test/lib/jdk/test/lib/thread/libVThreadPinner.c similarity index 68% rename from test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c rename to test/lib/jdk/test/lib/thread/libVThreadPinner.c index 2ac2064775c..958e636e3db 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c +++ b/test/lib/jdk/test/lib/thread/libVThreadPinner.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,17 @@ * questions. */ -#include +#include -JNIEXPORT void JNICALL -Java_gc_stress_gclocker_GCLockerStresser_fillWithRandomValues(JNIEnv* env, jclass clz, jbyteArray arr) { - jsize size = (*env)->GetArrayLength(env, arr); - jbyte* p = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); - jsize i; - for (i = 0; i < size; i++) { - p[i] = i % 128; - } - (*env)->ReleasePrimitiveArrayCritical(env, arr, p, 0); +#ifdef _WIN64 +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +/* + * Call a function with the given function pointer. + */ +EXPORT void call(void *(*f)(void)) { + (*f)(); } diff --git a/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java b/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java index 48f75a3ec81..c2f4e93313c 100644 --- a/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java +++ b/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -923,4 +923,9 @@ public double testDirectLoopGetDouble() { } return r; } + + @Benchmark + public int testHeapHashCode() { + return heapByteBuffer.hashCode(); + } } diff --git a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java index 67e51e9532d..62c45045585 100644 --- a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java +++ b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,11 +80,12 @@ public void init() throws Exception { KeyStore ks = TestCertificates.getKeyStore(); KeyStore ts = TestCertificates.getTrustStore(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance( + KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, new char[0]); - TrustManagerFactory tmf = - TrustManagerFactory.getInstance("SunX509"); + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ts); SSLContext sslCtx = SSLContext.getInstance(tlsVersion); diff --git a/test/micro/org/openjdk/bench/java/security/TestCertificates.java b/test/micro/org/openjdk/bench/java/security/TestCertificates.java index 50d8401c070..752f0442a93 100644 --- a/test/micro/org/openjdk/bench/java/security/TestCertificates.java +++ b/test/micro/org/openjdk/bench/java/security/TestCertificates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,12 +115,12 @@ class TestCertificates { private TestCertificates() {} public static KeyStore getKeyStore() throws GeneralSecurityException, IOException { - KeyStore result = KeyStore.getInstance("JKS"); + KeyStore result = KeyStore.getInstance(KeyStore.getDefaultType()); result.load(null, null); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate serverCert = cf.generateCertificate( new ByteArrayInputStream( - TestCertificates.SERVER_CERT.getBytes(StandardCharsets.ISO_8859_1))); + SERVER_CERT.getBytes(StandardCharsets.ISO_8859_1))); Certificate caCert = cf.generateCertificate( new ByteArrayInputStream( CA_CERT.getBytes(StandardCharsets.ISO_8859_1))); @@ -135,7 +135,7 @@ public static KeyStore getKeyStore() throws GeneralSecurityException, IOExceptio } public static KeyStore getTrustStore() throws GeneralSecurityException, IOException { - KeyStore result = KeyStore.getInstance("JKS"); + KeyStore result = KeyStore.getInstance(KeyStore.getDefaultType()); result.load(null, null); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate rootcaCert = cf.generateCertificate( diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java b/test/micro/org/openjdk/bench/vm/compiler/CMove.java similarity index 52% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java rename to test/micro/org/openjdk/bench/vm/compiler/CMove.java index 302bd203277..0f92a681c72 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java +++ b/test/micro/org/openjdk/bench/vm/compiler/CMove.java @@ -20,32 +20,40 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package org.openjdk.bench.vm.compiler; -package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGeneratorFactory; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; -/** - * This class represents a writer thread that emits log messages with LogCompilation. It saves and restores a currently - * parsed {@link LoggedMethod} if a {@link CompilePhaseBlock} was interrupted before reaching the block end tag. - * - * @see LoggedMethod - * @see CompilePhaseBlock - */ -class WriterThread { - private LoggedMethod loggedMethod = LoggedMethod.DONT_CARE; +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 1) +public class CMove { + static final int SIZE = 1000000; - public static boolean isWriterThreadLine(String line) { - return line.startsWith("