diff --git a/.github/scripts/gen-test-results.sh b/.github/scripts/gen-test-results.sh index 73edb8b3d11fe..9e85eef4dc08d 100644 --- a/.github/scripts/gen-test-results.sh +++ b/.github/scripts/gen-test-results.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -44,8 +44,8 @@ for test in $failures $errors; do base_path="$(echo "$test" | tr '#' '_')" report_file="$report_dir/$base_path.jtr" hs_err_files=$(ls $report_dir/$base_path/hs_err*.log 2> /dev/null || true) + replay_files=$(ls $report_dir/$base_path/replay*.log 2> /dev/null || true) echo "#### $test" - echo '
View test results' echo '' echo '```' @@ -73,6 +73,20 @@ for test in $failures $errors; do echo '' fi + if [[ "$replay_files" != "" ]]; then + echo '
View HotSpot replay file' + echo '' + for replay in $replay_files; do + echo '```' + echo "$replay:" + echo '' + cat "$replay" + echo '```' + done + + echo '
' + echo '' + fi done >> $GITHUB_STEP_SUMMARY # With many failures, the summary can easily exceed 1024 kB, the limit set by Github diff --git a/bin/blessed-modifier-order.sh b/bin/blessed-modifier-order.sh index 4e999e02506ca..548a89dbe14b8 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 69fb371a4770f..7fd530e9dbc45 100644 --- a/doc/building.html +++ b/doc/building.html @@ -753,6 +753,8 @@

Fontconfig

sudo apt-get install libfontconfig-dev.
  • To install on an rpm-based Linux, try running sudo yum install fontconfig-devel.
  • +
  • To install on Alpine Linux, try running +sudo apk add fontconfig-dev.
  • Use --with-fontconfig-include=<path> and --with-fontconfig=<path> if configure diff --git a/doc/building.md b/doc/building.md index abbd935f652ab..de410439446e1 100644 --- a/doc/building.md +++ b/doc/building.md @@ -572,6 +572,7 @@ required on all platforms except Windows and macOS. libfontconfig-dev`. * To install on an rpm-based Linux, try running `sudo yum install fontconfig-devel`. +* To install on Alpine Linux, try running `sudo apk add fontconfig-dev`. Use `--with-fontconfig-include=` and `--with-fontconfig=` if `configure` does not automatically locate the platform Fontconfig files. diff --git a/make/RunTests.gmk b/make/RunTests.gmk index b82d2b2b6015d..b0291e4eff4e7 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -620,11 +620,16 @@ define SetupRunMicroTestBody $1_MICRO_WARMUP_TIME := -w $$(MICRO_WARMUP_TIME) endif +# Microbenchmarks are executed from the root of the test image directory. +# This enables JMH tests to add dependencies using relative paths such as +# -Djava.library.path=micro/native + run-test-$1: pre-run-test $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ + $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ $$($1_MICRO_ITER) $$($1_MICRO_FORK) $$($1_MICRO_TIME) \ diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 289eec3356b91..7a24815d163f5 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -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 @@ -389,6 +389,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" CXXFLAGS="$ORG_CXXFLAGS" + + # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72 + UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11) + CXX="$cxx_filtered" ]) # Check if a compiler is of the toolchain type we expect, and save the version diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 349a04a089ee4..3fae951224e3b 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -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 @@ -199,7 +199,7 @@ AC_DEFUN([UTIL_GET_NON_MATCHING_VALUES], if test -z "$legal_values"; then $1="$2" else - result=`$GREP -Fvx "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fvx -- "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) @@ -226,7 +226,7 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES], if test -z "$illegal_values"; then $1="" else - result=`$GREP -Fx "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fx -- "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index a964045eb5225..5c29ee4db7587 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -548,6 +548,7 @@ $(BUILDDIR)/$(gcc_ver)/Makefile \ $(PATHPRE) $(ENVS) $(GCC_CFG) $(EXTRA_CFLAGS) \ $(CONFIG) \ --with-sysroot=$(SYSROOT) \ + --with-debug-prefix-map=$(OUTPUT_ROOT)=devkit \ --enable-languages=c,c++ \ --enable-shared \ --disable-nls \ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 8a461e647ab73..3393d9e00aa25 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -85,7 +85,7 @@ CFLAGS_VM_VERSION := \ DISABLED_WARNINGS_gcc := array-bounds comment delete-non-virtual-dtor \ empty-body implicit-fallthrough int-in-bool-context \ - maybe-uninitialized missing-field-initializers parentheses \ + maybe-uninitialized missing-field-initializers \ shift-negative-value unknown-pragmas DISABLED_WARNINGS_clang := sometimes-uninitialized \ diff --git a/make/test/BuildTestLibNative.gmk b/make/test/BuildTestLibNative.gmk index 00c7607913b1e..455936d163f3a 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 98101ee1e86bf..d8edb8743d7b5 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 @@ -857,6 +857,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/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 233f9b6af7c14..f637648b2279c 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. // @@ -8237,6 +8237,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/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index 558bd80a0e0c2..099dcdb4f2b16 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -156,8 +156,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 f5b46a5351973..d3ae7871f61f2 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. * @@ -195,7 +195,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; } @@ -359,20 +359,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/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 27bf35e12c87a..192a0d1ac1c9e 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -28,7 +28,6 @@ #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "gc/shared/collectedHeap.hpp" -#include "memory/resourceArea.hpp" #include "nativeInst_aarch64.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.hpp" @@ -189,8 +188,6 @@ void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); - ResourceMark rm; - int code_size = NativeInstruction::instruction_size; address addr_call = addr_at(0); bool reachable = Assembler::reachable_from_branch_at(addr_call, dest); assert(NativeCall::is_call_at(addr_call), "unexpected code at call site"); @@ -560,18 +557,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 1740fde772f0f..c0be84d3f5ce6 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/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index 6e345c96ce20c..c895ff5cc0ec1 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -197,7 +197,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { temp_reg, temp_reg2, itable_index, L_no_such_interface); // Reduce "estimate" such that "padding" does not drop below 8. - const ptrdiff_t estimate = 124; + const ptrdiff_t estimate = 144; const ptrdiff_t codesize = __ pc() - start_pc; slop_delta = (int)(estimate - codesize); slop_bytes += slop_delta; diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index c4197235987d5..e31ad91613a1a 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 b1b4199e88de0..6a3092f7b3b91 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 72993b3211f9d..999309c02258d 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 @@ -2640,8 +2640,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/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp index 7ef941ad0ff78..56f8fc9932e84 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 9191d03baf0ec..8a08c0d0e9c43 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/nativeInst_arm_32.cpp b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp index e5e5e89c2002b..23ee01d335264 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 804292c24b086..7006d7709813a 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/ppc/frame_ppc.hpp b/src/hotspot/cpu/ppc/frame_ppc.hpp index e2e2b9d015dde..d2c9927f119ee 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 e7dca45b3c35a..220b9c3241e01 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/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index ec91e86cd7c9a..44bb03aa6d87d 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -23,11 +23,10 @@ * */ -#include "gc/shared/gcArguments.hpp" -#include "gc/shared/gc_globals.hpp" -#include "macroAssembler_ppc.hpp" #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "gc/shared/gcArguments.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -38,6 +37,7 @@ #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "interpreter/interpreter.hpp" +#include "macroAssembler_ppc.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp index b83994ee8de94..7db34177d3acf 100644 --- a/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp @@ -22,8 +22,8 @@ * questions. */ -#include "asm/register.hpp" #include "precompiled.hpp" +#include "asm/register.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/codeBlob.hpp" #include "code/vmreg.inline.hpp" diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp index f60f3f147ae09..06754ccfdd7d2 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 378f4ea928a57..ec6f5a90a7211 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/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 22554972583e3..4a01a9c2ae455 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); @@ -815,6 +815,8 @@ enum operand_size { int8, int16, int32, uint32, int64 }; INSN(fsqrt_s, 0b1010011, 0b00000, 0b0101100); INSN(fsqrt_d, 0b1010011, 0b00000, 0b0101101); + INSN(fcvt_s_h, 0b1010011, 0b00010, 0b0100000); + INSN(fcvt_h_s, 0b1010011, 0b00000, 0b0100010); INSN(fcvt_s_d, 0b1010011, 0b00001, 0b0100000); INSN(fcvt_d_s, 0b1010011, 0b00000, 0b0100001); #undef INSN @@ -1071,6 +1073,7 @@ enum operand_size { int8, int16, int32, uint32, int64 }; emit(insn); \ } + INSN(fmv_h_x, 0b1010011, 0b000, 0b00000, 0b1111010); INSN(fmv_w_x, 0b1010011, 0b000, 0b00000, 0b1111000); INSN(fmv_d_x, 0b1010011, 0b000, 0b00000, 0b1111001); @@ -1108,8 +1111,10 @@ enum fclass_mask { emit(insn); \ } + INSN(fclass_h, 0b1010011, 0b001, 0b00000, 0b1110010); INSN(fclass_s, 0b1010011, 0b001, 0b00000, 0b1110000); INSN(fclass_d, 0b1010011, 0b001, 0b00000, 0b1110001); + INSN(fmv_x_h, 0b1010011, 0b000, 0b00000, 0b1110010); INSN(fmv_x_w, 0b1010011, 0b000, 0b00000, 0b1110000); INSN(fmv_x_d, 0b1010011, 0b000, 0b00000, 0b1110001); @@ -1156,10 +1161,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); \ @@ -1334,6 +1337,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 @@ -1689,7 +1693,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) { \ @@ -1731,14 +1734,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 @@ -1749,6 +1767,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 @@ -1794,9 +1815,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 @@ -1820,6 +1843,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. @@ -1869,9 +1941,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); @@ -2583,6 +2655,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 // -------------------------- @@ -2917,6 +2998,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(); } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 711eb2100912b..0617c37687ffa 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1783,6 +1783,52 @@ void C2_MacroAssembler::signum_fp(FloatRegister dst, FloatRegister one, bool is_ bind(done); } +static void float16_to_float_slow_path(C2_MacroAssembler& masm, C2GeneralStub& stub) { +#define __ masm. + FloatRegister dst = stub.data<0>(); + Register src = stub.data<1>(); + Register tmp = stub.data<2>(); + __ bind(stub.entry()); + + // following instructions mainly focus on NaN, as riscv does not handle + // NaN well with fcvt, but the code also works for Inf at the same time. + + // construct a NaN in 32 bits from the NaN in 16 bits, + // we need the payloads of non-canonical NaNs to be preserved. + __ mv(tmp, 0x7f800000); + // sign-bit was already set via sign-extension if necessary. + __ slli(t0, src, 13); + __ orr(tmp, t0, tmp); + __ fmv_w_x(dst, tmp); + + __ j(stub.continuation()); +#undef __ +} + +// j.l.Float.float16ToFloat +void C2_MacroAssembler::float16_to_float(FloatRegister dst, Register src, Register tmp) { + auto stub = C2CodeStub::make(dst, src, tmp, 20, float16_to_float_slow_path); + + // in riscv, NaN needs a special process as fcvt does not work in that case. + // in riscv, Inf does not need a special process as fcvt can handle it correctly. + // but we consider to get the slow path to process NaN and Inf at the same time, + // as both of them are rare cases, and if we try to get the slow path to handle + // only NaN case it would sacrifise the performance for normal cases, + // i.e. non-NaN and non-Inf cases. + + // check whether it's a NaN or +/- Inf. + mv(t0, 0x7c00); + andr(tmp, src, t0); + // jump to stub processing NaN and Inf cases. + beq(t0, tmp, stub->entry()); + + // non-NaN or non-Inf cases, just use built-in instructions. + fmv_h_x(dst, src); + fcvt_s_h(dst, dst); + + bind(stub->continuation()); +} + void C2_MacroAssembler::signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen) { vsetvli_helper(bt, vlen); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 4940ce5fe9e94..7309c59110a0b 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -172,8 +172,11 @@ void signum_fp(FloatRegister dst, FloatRegister one, bool is_double); + void float16_to_float(FloatRegister dst, Register src, Register tmp); + void signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen); + // intrinsic methods implemented by rvv instructions // compress bits, i.e. j.l.Integer/Long::compress. diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp index ae6242a75bdd8..0c0659d1eee13 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 dfec388019216..33727a8c6d0a7 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/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 60456c37ffe75..01cd2296d9e41 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, UseZfh, false, "Use Zfh 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") \ @@ -113,6 +114,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/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 50ad3efbdb450..ce336c16aa718 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. @@ -4678,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); + switch (bits) { + case 32: + sext_w(dst, src); return; - } else if (bits == 16) { - sext_h(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, @@ -4891,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()))); @@ -4935,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 3e0206746242c..d283654e6e179 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 @@ -1361,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); @@ -1376,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/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 2b2e5606c81ea..c29ac1a04fae1 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 3c6ec1cf588b3..48bbb2b3b181d 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 d5a95b2e3ba5b..550e7947cc5e6 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 @@ -1931,6 +1932,9 @@ bool Matcher::match_rule_supported(int opcode) { case Op_FmaVF: case Op_FmaVD: return UseFMA; + + case Op_ConvHF2F: + return UseZfh; } return true; // Per default match rules are supported. @@ -8274,6 +8278,20 @@ instruct convD2F_reg(fRegF dst, fRegD src) %{ ins_pipe(fp_d2f); %} +// single <-> half precision + +instruct convHF2F_reg_reg(fRegF dst, iRegINoSp src, iRegINoSp tmp) %{ + match(Set dst (ConvHF2F src)); + effect(TEMP tmp); + format %{ "fmv.h.x $dst, $src\t# move source from $src to $dst\n\t" + "fcvt.s.h $dst, $dst\t# convert half to single precision" + %} + ins_encode %{ + __ float16_to_float($dst$$FloatRegister, $src$$Register, $tmp$$Register); + %} + ins_pipe(pipe_slow); +%} + // float <-> int instruct convF2I_reg_reg(iRegINoSp dst, fRegF src) %{ @@ -8674,7 +8692,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" %} @@ -8692,7 +8710,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" %} @@ -8710,7 +8728,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" %} @@ -8728,7 +8746,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" %} diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index be5fd98335329..4bd33d08f8928 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 @@ -4862,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 41ec15a8634b2..390ba51ee4f34 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -81,6 +81,9 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UseZbs)) { FLAG_SET_DEFAULT(UseZbs, true); } + if (FLAG_IS_DEFAULT(UseZfh)) { + FLAG_SET_DEFAULT(UseZfh, true); + } if (FLAG_IS_DEFAULT(UseZic64b)) { FLAG_SET_DEFAULT(UseZic64b, true); } @@ -146,26 +149,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 +260,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 +275,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 diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 290b44eb0efe9..de85fb166f834 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -105,11 +105,16 @@ class VM_Version : public Abstract_VM_Version { // Zbc Carry-less multiplication // Zbs Single-bit instructions // + // Zfh Half-Precision Floating-Point instructions + // // Zicsr Control and Status Register (CSR) Instructions // Zifencei Instruction-Fetch Fence // 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 +122,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,6 +144,8 @@ 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_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \ 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)) \ diff --git a/src/hotspot/cpu/s390/frame_s390.hpp b/src/hotspot/cpu/s390/frame_s390.hpp index 3f81cd254d080..06433d9136fdc 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 91a6917c3191e..178f7f908491c 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/nativeInst_s390.hpp b/src/hotspot/cpu/s390/nativeInst_s390.hpp index 65bfe4993705e..abad50da8b421 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/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 42f675f83c355..3817c38f4ba3b 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1089,7 +1089,8 @@ void C2_MacroAssembler::vminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); - assert_different_registers(a, b, tmp, atmp, btmp); + assert_different_registers(a, tmp, atmp, btmp); + assert_different_registers(b, tmp, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); @@ -1176,7 +1177,8 @@ void C2_MacroAssembler::evminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); - assert_different_registers(dst, a, b, atmp, btmp); + assert_different_registers(dst, a, atmp, btmp); + assert_different_registers(dst, b, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index 122f640a92a35..44c8574c54002 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.hpp @@ -149,8 +149,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 70008e1011779..f69803d579d43 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -343,20 +343,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/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp index 1df8c78c99d57..b59f424625636 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 938a10cb63d75..f8cbf70f18961 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.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index de759d2ff5761..3ecbb43f7f518 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -26,6 +26,7 @@ #include "asm/macroAssembler.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/globalDefinitions.hpp" #include "vmreg_x86.inline.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" @@ -59,9 +60,16 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas __ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - // check if locked - __ testptr(result, markWord::unlocked_value); - __ jcc(Assembler::zero, slowCase); + + if (LockingMode == LM_LIGHTWEIGHT) { + // check if monitor + __ testptr(result, markWord::monitor_value); + __ jcc(Assembler::notZero, slowCase); + } else { + // check if locked + __ testptr(result, markWord::unlocked_value); + __ jcc(Assembler::zero, slowCase); + } // get hash #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 8d656c136aa89..caa82aab99c2d 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -8965,6 +8965,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 45cc785a5394d..f2e9c042b244f 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 @@ -13161,7 +13161,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 %{ @@ -13171,7 +13171,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 %{ @@ -13180,7 +13180,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 %{ @@ -13189,7 +13189,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 %{ @@ -13352,7 +13352,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 %{ @@ -13362,7 +13362,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 %{ @@ -13371,7 +13371,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 %{ @@ -13380,7 +13380,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 %{ @@ -13571,7 +13571,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 %{ @@ -13581,7 +13581,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 %{ @@ -13590,7 +13590,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 %{ @@ -13600,7 +13600,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/zero/frame_zero.hpp b/src/hotspot/cpu/zero/frame_zero.hpp index 87511ab212e1f..a4815d2c10ba9 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 1b504cfa6663e..944084f70af40 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/nativeInst_zero.hpp b/src/hotspot/cpu/zero/nativeInst_zero.hpp index 5b2c9743cf904..77a7d511ac5e8 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 c75828c0c22f9..adaab8914a7fc 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1118,7 +1118,9 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } if (!filename || strlen(filename) == 0) { - ::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1); + if (ebuf != nullptr && ebuflen > 0) { + ::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1); + } return nullptr; } @@ -1133,8 +1135,9 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } void* result; + const char* error_report = nullptr; JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) - result = ::dlopen(filename, dflags); + result = Aix_dlopen(filename, dflags, &error_report); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Reload dll cache. Don't do this in signal handling. @@ -1143,7 +1146,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { return result; } else { // error analysis when dlopen fails - const char* error_report = ::dlerror(); if (error_report == nullptr) { error_report = "dlerror returned no error description"; } @@ -3026,31 +3028,3 @@ void os::jfr_report_memory_info() {} #endif // INCLUDE_JFR -// Simulate the library search algorithm of dlopen() (in os::dll_load) -int os::Aix::stat64x_via_LIBPATH(const char* path, struct stat64x* stat) { - if (path[0] == '/' || - (path[0] == '.' && (path[1] == '/' || - (path[1] == '.' && path[2] == '/')))) { - return stat64x(path, stat); - } - - const char* env = getenv("LIBPATH"); - if (env == nullptr || *env == 0) - return -1; - - int ret = -1; - size_t libpathlen = strlen(env); - char* libpath = NEW_C_HEAP_ARRAY(char, libpathlen + 1, mtServiceability); - char* combined = NEW_C_HEAP_ARRAY(char, libpathlen + strlen(path) + 1, mtServiceability); - char *saveptr, *token; - strcpy(libpath, env); - for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) { - sprintf(combined, "%s/%s", token, path); - if (0 == (ret = stat64x(combined, stat))) - break; - } - - FREE_C_HEAP_ARRAY(char*, combined); - FREE_C_HEAP_ARRAY(char*, libpath); - return ret; -} diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index f2596874b051a..a1db2b2be3cc7 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -175,8 +175,6 @@ class os::Aix { static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size, address& lastpc); static void* resolve_function_descriptor(void* p); - // Simulate the library search algorithm of dlopen() (in os::dll_load) - static int stat64x_via_LIBPATH(const char* path, struct stat64x* stat); }; #endif // OS_AIX_OS_AIX_HPP diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index ab84dc8102770..68233097b4957 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -21,6 +21,12 @@ * questions. * */ +// needs to be defined first, so that the implicit loaded xcoff.h header defines +// the right structures to analyze the loader header of 64 Bit executable files +// this is needed for rtv_linkedin_libpath() to get the linked (burned) in library +// search path of an XCOFF executable +#define __XCOFF64__ +#include #include "asm/assembler.hpp" #include "compiler/disassembler.hpp" @@ -891,3 +897,275 @@ bool AixMisc::query_stack_bounds_for_current_thread(stackbounds_t* out) { return true; } + +// variables needed to emulate linux behavior in os::dll_load() if library is loaded twice +static pthread_mutex_t g_handletable_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct TableLocker { + TableLocker() { pthread_mutex_lock(&g_handletable_mutex); } + ~TableLocker() { pthread_mutex_unlock(&g_handletable_mutex); } +}; +struct handletableentry{ + void* handle; + ino64_t inode; + dev64_t devid; + uint refcount; +}; +constexpr unsigned init_num_handles = 128; +static unsigned max_handletable = 0; +static unsigned g_handletable_used = 0; +// We start with an empty array. At first use we will dynamically allocate memory for 128 entries. +// If this table is full we dynamically reallocate a memory reagion of double size, and so on. +static struct handletableentry* p_handletable = nullptr; + +// get the library search path burned in to the executable file during linking +// If the libpath cannot be retrieved return an empty path +static const char* rtv_linkedin_libpath() { + constexpr int bufsize = 4096; + static char buffer[bufsize]; + static const char* libpath = 0; + + // we only try to retrieve the libpath once. After that try we + // let libpath point to buffer, which then contains a valid libpath + // or an empty string + if (libpath != nullptr) { + return libpath; + } + + // retrieve the path to the currently running executable binary + // to open it + snprintf(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); + FILE* f = nullptr; + struct xcoffhdr the_xcoff; + struct scnhdr the_scn; + struct ldhdr the_ldr; + constexpr size_t xcoffsz = FILHSZ + _AOUTHSZ_EXEC; + STATIC_ASSERT(sizeof(the_xcoff) == xcoffsz); + STATIC_ASSERT(sizeof(the_scn) == SCNHSZ); + STATIC_ASSERT(sizeof(the_ldr) == LDHDRSZ); + // read the generic XCOFF header and analyze the substructures + // to find the burned in libpath. In any case of error perform the assert + if (nullptr == (f = fopen(buffer, "r")) || + xcoffsz != fread(&the_xcoff, 1, xcoffsz, f) || + the_xcoff.filehdr.f_magic != U64_TOCMAGIC || + 0 != fseek(f, (FILHSZ + the_xcoff.filehdr.f_opthdr + (the_xcoff.aouthdr.o_snloader -1)*SCNHSZ), SEEK_SET) || + SCNHSZ != fread(&the_scn, 1, SCNHSZ, f) || + 0 != strcmp(the_scn.s_name, ".loader") || + 0 != fseek(f, the_scn.s_scnptr, SEEK_SET) || + LDHDRSZ != fread(&the_ldr, 1, LDHDRSZ, f) || + 0 != fseek(f, the_scn.s_scnptr + the_ldr.l_impoff, SEEK_SET) || + 0 == fread(buffer, 1, bufsize, f)) { + buffer[0] = 0; + assert(false, "could not retrieve burned in library path from executables loader section"); + } + + if (f) { + fclose(f); + } + libpath = buffer; + + return libpath; +} + +// Simulate the library search algorithm of dlopen() (in os::dll_load) +static bool search_file_in_LIBPATH(const char* path, struct stat64x* stat) { + if (path == nullptr) + return false; + + char* path2 = os::strdup(path); + // if exist, strip off trailing (shr_64.o) or similar + char* substr; + if (path2[strlen(path2) - 1] == ')' && (substr = strrchr(path2, '('))) { + *substr = 0; + } + + bool ret = false; + // If FilePath contains a slash character, FilePath is used directly, + // and no directories are searched. + // But if FilePath does not start with / or . we have to prepend it with ./ + if (strchr(path2, '/')) { + stringStream combined; + if (*path2 == '/' || *path2 == '.') { + combined.print("%s", path2); + } else { + combined.print("./%s", path2); + } + ret = (0 == stat64x(combined.base(), stat)); + os::free(path2); + return ret; + } + + const char* env = getenv("LIBPATH"); + if (env == nullptr) { + // no LIBPATH, try with LD_LIBRARY_PATH + env = getenv("LD_LIBRARY_PATH"); + } + + stringStream Libpath; + if (env == nullptr) { + // no LIBPATH or LD_LIBRARY_PATH given -> try only with burned in libpath + Libpath.print("%s", rtv_linkedin_libpath()); + } else if (*env == 0) { + // LIBPATH or LD_LIBRARY_PATH given but empty -> try first with burned + // in libpath and with current working directory second + Libpath.print("%s:.", rtv_linkedin_libpath()); + } else { + // LIBPATH or LD_LIBRARY_PATH given with content -> try first with + // LIBPATH or LD_LIBRARY_PATH and second with burned in libpath. + // No check against current working directory + Libpath.print("%s:%s", env, rtv_linkedin_libpath()); + } + + char* libpath = os::strdup(Libpath.base()); + + char *saveptr, *token; + for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) { + stringStream combined; + combined.print("%s/%s", token, path2); + if ((ret = (0 == stat64x(combined.base(), stat)))) + break; + } + + os::free(libpath); + os::free(path2); + return ret; +} + +// specific AIX versions for ::dlopen() and ::dlclose(), which handles the struct g_handletable +// This way we mimic dl handle equality for a library +// opened a second time, as it is implemented on other platforms. +void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { + assert(error_report != nullptr, "error_report is nullptr"); + void* result; + struct stat64x libstat; + + if (false == search_file_in_LIBPATH(filename, &libstat)) { + // file with filename does not exist + #ifdef ASSERT + result = ::dlopen(filename, Flags); + assert(result == nullptr, "dll_load: Could not stat() file %s, but dlopen() worked; Have to improve stat()", filename); + #endif + *error_report = "Could not load module .\nSystem error: No such file or directory"; + return nullptr; + } + else { + unsigned i = 0; + TableLocker lock; + // check if library belonging to filename is already loaded. + // If yes use stored handle from previous ::dlopen() and increase refcount + for (i = 0; i < g_handletable_used; i++) { + if ((p_handletable + i)->handle && + (p_handletable + i)->inode == libstat.st_ino && + (p_handletable + i)->devid == libstat.st_dev) { + (p_handletable + i)->refcount++; + result = (p_handletable + i)->handle; + break; + } + } + if (i == g_handletable_used) { + // library not yet loaded. Check if there is space left in array + // to store new ::dlopen() handle + if (g_handletable_used == max_handletable) { + // No place in array anymore; increase array. + unsigned new_max = MAX2(max_handletable * 2, init_num_handles); + struct handletableentry* new_tab = (struct handletableentry*)::realloc(p_handletable, new_max * sizeof(struct handletableentry)); + assert(new_tab != nullptr, "no more memory for handletable"); + if (new_tab == nullptr) { + *error_report = "dlopen: no more memory for handletable"; + return nullptr; + } + max_handletable = new_max; + p_handletable = new_tab; + } + // Library not yet loaded; load it, then store its handle in handle table + result = ::dlopen(filename, Flags); + if (result != nullptr) { + g_handletable_used++; + (p_handletable + i)->handle = result; + (p_handletable + i)->inode = libstat.st_ino; + (p_handletable + i)->devid = libstat.st_dev; + (p_handletable + i)->refcount = 1; + } + else { + // error analysis when dlopen fails + *error_report = ::dlerror(); + if (*error_report == nullptr) { + *error_report = "dlerror returned no error description"; + } + } + } + } + return result; +} + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + unsigned i = 0; + bool res = false; + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + { + TableLocker lock; + // try to find handle in array, which means library was loaded by os::dll_load() call + for (i = 0; i < g_handletable_used; i++) { + if ((p_handletable + i)->handle == libhandle) { + // handle found, decrease refcount + assert((p_handletable + i)->refcount > 0, "Sanity"); + (p_handletable + i)->refcount--; + if ((p_handletable + i)->refcount > 0) { + // if refcount is still >0 then we have to keep library and just return true + return true; + } + // refcount == 0, so we have to ::dlclose() the lib + // and delete the entry from the array. + break; + } + } + + // If we reach this point either the libhandle was found with refcount == 0, or the libhandle + // was not found in the array at all. In both cases we have to ::dlclose the lib and perform + // the error handling. In the first case we then also have to delete the entry from the array + // while in the second case we simply have to nag. + res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + assert(false, "os::pd_dll_unload() ::dlclose() failed"); + } + + if (i < g_handletable_used) { + if (res) { + // First case: libhandle was found (with refcount == 0) and ::dlclose successful, + // so delete entry from array + g_handletable_used--; + // If the entry was the last one of the array, the previous g_handletable_used-- + // is sufficient to remove the entry from the array, otherwise we move the last + // entry of the array to the place of the entry we want to remove and overwrite it + if (i < g_handletable_used) { + *(p_handletable + i) = *(p_handletable + g_handletable_used); + (p_handletable + g_handletable_used)->handle = nullptr; + } + } + } + else { + // Second case: libhandle was not found (library was not loaded by os::dll_load()) + // therefore nag + assert(false, "os::pd_dll_unload() library was not loaded by os::dll_load()"); + } + } + + // Update the dll cache + LoadedLibraries::reload(); + + return res; +} // end: os::pd_dll_unload() + diff --git a/src/hotspot/os/aix/porting_aix.hpp b/src/hotspot/os/aix/porting_aix.hpp index 2c4c0e002a8fa..109eceee3fca5 100644 --- a/src/hotspot/os/aix/porting_aix.hpp +++ b/src/hotspot/os/aix/porting_aix.hpp @@ -115,4 +115,6 @@ class AixMisc { }; +void* Aix_dlopen(const char* filename, int Flags, const char** error_report); + #endif // OS_AIX_PORTING_AIX_HPP diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 2f7f31157e89e..958372e20a5ce 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2530,3 +2530,25 @@ void os::jfr_report_memory_info() { } #endif // INCLUDE_JFR + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + bool res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + } + + return res; +} // end: os::pd_dll_unload() diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 6c5470445f18c..3cc2141f176b2 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 146d7237a9070..37a1f476bde8b 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 fae65da2a58fe..c7550136f48bd 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 1a02bbe95d249..1c433be1c2391 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 bb6b538c216e3..b12b4ce6512cd 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 c70c96c678ac6..14bfa5a7678d4 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 776167993cba1..bb03ba3b005a2 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 5117ccac84bb1..65574294b4099 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2216,7 +2216,7 @@ 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_pdm_size", + _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); @@ -2398,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); @@ -5467,3 +5469,25 @@ bool os::trim_native_heap(os::size_change_t* rss_change) { return false; // musl #endif } + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + bool res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + } + + return res; +} // end: os::pd_dll_unload() diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 960fb465590cc..1158392fa4964 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -56,6 +56,7 @@ #ifdef AIX #include "loadlib_aix.hpp" +#include "os_aix.hpp" #endif #ifdef LINUX #include "os_linux.hpp" @@ -731,27 +732,22 @@ void os::dll_unload(void *lib) { if (l_path == nullptr) { l_path = ""; } - int res = ::dlclose(lib); - if (res == 0) { + char ebuf[1024]; + bool res = os::pd_dll_unload(lib, ebuf, sizeof(ebuf)); + + if (res) { Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); JFR_ONLY(unload_event.set_result(true);) } else { - const char* error_report = ::dlerror(); - if (error_report == nullptr) { - error_report = "dlerror returned no error description"; - } - Events::log_dll_message(nullptr, "Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", - l_path, p2i(lib), error_report); + l_path, p2i(lib), ebuf); log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", - l_path, p2i(lib), error_report); - JFR_ONLY(unload_event.set_error_msg(error_report);) + l_path, p2i(lib), ebuf); + JFR_ONLY(unload_event.set_error_msg(ebuf);) } - // Update the dll cache - AIX_ONLY(LoadedLibraries::reload()); LINUX_ONLY(os::free(l_pathdup)); } 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 df5a42fd118b9..fbd7c4eccd403 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/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 6e93406b1a353..5230a06e43f63 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,10 @@ void VM_Version::rivos_features() { ext_Zbb.enable_feature(); ext_Zbs.enable_feature(); + ext_Zcb.enable_feature(); + + ext_Zfh.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 8e2366e5d09ff..ecbf472c59ef4 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 53fb5fbcf9efe..bef1fae7f7496 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" @@ -388,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(); @@ -579,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) @@ -626,7 +625,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); } @@ -652,6 +651,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 b0753a94d1ba7..f344695509ee1 100644 --- a/src/hotspot/share/c1/c1_Compilation.hpp +++ b/src/hotspot/share/c1/c1_Compilation.hpp @@ -34,6 +34,7 @@ #include "memory/resourceArea.hpp" #include "runtime/deoptimization.hpp" +class CompilationFailureInfo; class CompilationResourceObj; class XHandlers; class ExceptionInfo; @@ -85,6 +86,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; @@ -212,6 +214,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_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index fb2aa28ec86a3..6e5fb99242c8c 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 @@ -1315,8 +1315,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()) ? state_before : nullptr, is_bb)); 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()) { @@ -1451,7 +1451,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"); } } } @@ -1500,7 +1500,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"); } } } @@ -2316,7 +2316,6 @@ void GraphBuilder::instance_of(int klass_index) { 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), bci); kill_all(); } @@ -3510,6 +3509,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; @@ -3526,9 +3534,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; @@ -3539,9 +3545,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 @@ -3559,9 +3563,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; } diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index 7e46f9d56034b..9e9195a0d60d0 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 74d5c2e3f3c65..0a75fa39bf607 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 @@ -60,7 +60,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/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 3b50e01479718..c2bfec3dfeb18 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.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 @@ -576,12 +576,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; + } } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 3d2062093c6b7..fd84563008ccf 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -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 @@ -89,6 +89,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; diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp index 5c39cb58f9ff1..fc12cc0259b71 100644 --- a/src/hotspot/share/ci/ciEnv.hpp +++ b/src/hotspot/share/ci/ciEnv.hpp @@ -362,7 +362,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() @@ -444,7 +444,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/code/codeCache.inline.hpp b/src/hotspot/share/code/codeCache.inline.hpp index bea66cf00106a..5ab7187cd2685 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 b493df73ba88c..28c02d8578c55 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 diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index cb185446cccb2..b18077fddfdef 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1137,10 +1137,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); } } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index d2e70fbd6db02..bfb3db72d7265 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 0000000000000..e3f3353589e54 --- /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/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java b/src/hotspot/share/compiler/compilationFailureInfo.hpp similarity index 50% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java rename to src/hotspot/share/compiler/compilationFailureInfo.hpp index 76b096a3f3dd0..3de62eb69da5a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java +++ b/src/hotspot/share/compiler/compilationFailureInfo.hpp @@ -1,5 +1,6 @@ /* * 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 @@ -19,32 +20,38 @@ * 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.lib.ir_framework.driver.irmatching.parser.hotspot; +#ifndef SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP +#define SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP -import compiler.lib.ir_framework.TestFramework; +#if defined(COMPILER1) || defined(COMPILER2) -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/nativeCallStack.hpp" -/** - * This class keeps track of all {@link WriterThread} instances. - */ -class WriterThreads { - private final Map mapIdToThread = new HashMap<>(); - - WriterThread parse(String line) { - int writerThreadId = parseWriterThreadId(line); - return mapIdToThread.computeIfAbsent(writerThreadId, c -> new WriterThread()); - } - - 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)); - } -} +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/compilerDefinitions.inline.hpp b/src/hotspot/share/compiler/compilerDefinitions.inline.hpp index ed456a4215720..d490387672dad 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 7f1f08b68ef65..71b475392cf69 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/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index a2097041b2093..4f759b4a6069e 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 09d901f283c70..54f87fd3b71dd 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/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index ec32f8b589b5c..b52bfdfbb0817 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -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 @@ -403,7 +403,7 @@ class G1PrepareEvacuationTask : public WorkerTask { _g1h->register_region_with_region_attr(hr); } log_debug(gc, humongous)("Humongous region %u (object size %zu @ " PTR_FORMAT ") remset %zu code roots %zu " - "marked %d pinned count %u reclaim candidate %d type array %d", + "marked %d pinned count %zu reclaim candidate %d type array %d", index, cast_to_oop(hr->bottom())->size() * HeapWordSize, p2i(hr->bottom()), diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index 29fe5031a354a..69040028d98c5 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -424,7 +424,7 @@ void HeapRegion::print_on(outputStream* st) const { st->print("|-"); } } - st->print("|%3u", Atomic::load(&_pinned_object_count)); + st->print("|%3zu", Atomic::load(&_pinned_object_count)); st->print_cr(""); } diff --git a/src/hotspot/share/gc/g1/heapRegion.hpp b/src/hotspot/share/gc/g1/heapRegion.hpp index 2706b814000a5..725433215c444 100644 --- a/src/hotspot/share/gc/g1/heapRegion.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,7 +257,7 @@ class HeapRegion : public CHeapObj { uint _node_index; // Number of objects in this region that are currently pinned. - volatile uint _pinned_object_count; + volatile size_t _pinned_object_count; void report_region_type_change(G1HeapRegionTraceType::Type to); @@ -408,7 +408,7 @@ class HeapRegion : public CHeapObj { bool is_old_or_humongous() const { return _type.is_old_or_humongous(); } - uint pinned_count() const { return Atomic::load(&_pinned_object_count); } + size_t pinned_count() const { return Atomic::load(&_pinned_object_count); } bool has_pinned_objects() const { return pinned_count() > 0; } void set_free(); diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index ec68407b546bd..4a42b9221829c 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -554,11 +554,11 @@ inline void HeapRegion::record_surv_words_in_group(size_t words_survived) { } inline void HeapRegion::increment_pinned_object_count() { - Atomic::add(&_pinned_object_count, 1u, memory_order_relaxed); + Atomic::add(&_pinned_object_count, (size_t)1, memory_order_relaxed); } inline void HeapRegion::decrement_pinned_object_count() { - Atomic::sub(&_pinned_object_count, 1u, memory_order_relaxed); + Atomic::sub(&_pinned_object_count, (size_t)1, memory_order_relaxed); } #endif // SHARE_GC_G1_HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index 94ade0f387c00..9ce61531989ee 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -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 @@ -41,7 +41,7 @@ nonstatic_field(HeapRegion, _bottom, HeapWord* const) \ nonstatic_field(HeapRegion, _top, HeapWord* volatile) \ nonstatic_field(HeapRegion, _end, HeapWord* const) \ - nonstatic_field(HeapRegion, _pinned_object_count, volatile uint) \ + volatile_nonstatic_field(HeapRegion, _pinned_object_count, size_t) \ \ nonstatic_field(HeapRegionType, _tag, HeapRegionType::Tag volatile) \ \ diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index be6d9a501b575..15287437cff43 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -583,12 +583,6 @@ void PSAdaptiveSizePolicy::adjust_eden_for_minor_pause_time(size_t* desired_eden 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); } } @@ -609,12 +603,6 @@ void PSAdaptiveSizePolicy::adjust_promo_for_pause_time(size_t* desired_promo_siz set_change_old_gen_for_maj_pauses(decrease_old_gen_for_maj_pauses_true); promo_heap_delta = promo_decrement_aligned_down(*desired_promo_size_ptr); *desired_promo_size_ptr = _promo_size - promo_heap_delta; - } else { - // EXPERIMENTAL ADJUSTMENT - // Only record that the estimator indicated such an action. - // *desired_promo_size_ptr = _promo_size + - // promo_increment_aligned_up(*desired_promo_size_ptr); - set_change_old_gen_for_maj_pauses(increase_old_gen_for_maj_pauses_true); } } @@ -700,14 +688,6 @@ void PSAdaptiveSizePolicy::adjust_promo_for_throughput(bool is_full_gc, set_change_old_gen_for_throughput( increase_old_gen_for_throughput_true); _old_gen_change_for_major_throughput++; - } else { - // EXPERIMENTAL ADJUSTMENT - // Record that decreasing the old gen size would decrease - // the major collection cost but don't do it. - // *desired_promo_size_ptr = _promo_size - - // promo_decrement_aligned_down(*desired_promo_size_ptr); - set_change_old_gen_for_throughput( - decrease_old_gen_for_throughput_true); } break; @@ -787,14 +767,6 @@ void PSAdaptiveSizePolicy::adjust_eden_for_throughput(bool is_full_gc, set_change_young_gen_for_throughput( increase_young_gen_for_througput_true); _young_gen_change_for_minor_throughput++; - } else { - // EXPERIMENTAL ADJUSTMENT - // Record that decreasing the young gen size would decrease - // the minor collection cost but don't do it. - // *desired_eden_size_ptr = _eden_size - - // eden_decrement_aligned_down(*desired_eden_size_ptr); - set_change_young_gen_for_throughput( - decrease_young_gen_for_througput_true); } break; default: diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 8946362026a29..e45b60851124f 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -415,8 +415,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), @@ -425,16 +425,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; } @@ -467,12 +467,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(); @@ -530,7 +529,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; diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 4cee322a589e4..94995bd4f195c 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/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 149acc1a4297f..19f688852385b 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -272,9 +272,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 fd830b831552f..730d31893d54c 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, @@ -96,9 +99,7 @@ class PSPushContentsClosure: public BasicOopIterateClosure { PSPushContentsClosure(PSPromotionManager* pm) : BasicOopIterateClosure(PSScavenge::reference_processor()), _pm(pm) {} template void do_oop_work(T* p) { - if (PSScavenge::should_scavenge(p)) { - _pm->claim_or_forward_depth(p); - } + _pm->claim_or_forward_depth(p); } virtual void do_oop(oop* p) { do_oop_work(p); } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index b569fbac48f0f..964c7661d311b 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -1104,11 +1104,6 @@ const char* DefNewGeneration::name() const { return "def new generation"; } -// Moved from inline file as they are not called inline -ContiguousSpace* DefNewGeneration::first_compaction_space() const { - return eden(); -} - HeapWord* DefNewGeneration::allocate(size_t word_size, bool is_tlab) { // This is the slow-path allocation for the DefNewGeneration. // Most allocations are fast-path in compiled code. diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index e9586993e547b..8203c62518395 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -168,8 +168,6 @@ class DefNewGeneration: public Generation { ContiguousSpace* from() const { return _from_space; } ContiguousSpace* to() const { return _to_space; } - virtual ContiguousSpace* first_compaction_space() const; - // Space enquiries size_t capacity() const; size_t used() const; @@ -256,8 +254,8 @@ class DefNewGeneration: public Generation { // completed. Even if this method returns true, a collection // may not be guaranteed to succeed, and the system should be // able to safely unwind and recover from that failure, albeit - // at some additional cost. Override superclass's implementation. - virtual bool collection_attempt_is_safe(); + // at some additional cost. + bool collection_attempt_is_safe(); virtual void collect(bool full, bool clear_all_soft_refs, diff --git a/src/hotspot/share/gc/serial/genMarkSweep.cpp b/src/hotspot/share/gc/serial/genMarkSweep.cpp index fb55116ab816b..28ba4615f73a2 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); @@ -241,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); - // Adjust the pointers to reflect the new locations - GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer()); + WeakProcessor::oops_do(&adjust_pointer_closure); - ClassLoaderDataGraph::verify_claimed_marks_cleared(ClassLoaderData::_claim_stw_fullgc_adjust); + adjust_marks(); + compacter.phase3_adjust_pointers(); + } - 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); + { + // All pointers are now adjusted, move objects accordingly + GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer); - gch->gen_process_weak_roots(&adjust_pointer_closure); + compacter.phase4_compact(); + } - adjust_marks(); - GenAdjustPointersClosure blk; - gch->generation_iterate(&blk, true); + restore_marks(); + + // Set saved marks for allocation profiler (and other things? -- dld) + // (Should this be in general part?) + gch->save_marks(); + + deallocate_stacks(); + + MarkSweep::_string_dedup_requests->flush(); + + bool is_young_gen_empty = (gch->young_gen()->used() == 0); + gch->rem_set()->maintain_old_to_young_invariant(gch->old_gen(), is_young_gen_empty); + + gch->prune_scavengable_nmethods(); + + // 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 be830318bd0d9..520e801057389 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 aa3c804ba3c20..302f8f231e7be 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 63eefae720bbb..bba9ac810c26d 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.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 @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_GC_SHARED_GENERATION_HPP -#define SHARE_GC_SHARED_GENERATION_HPP +#ifndef SHARE_GC_SERIAL_GENERATION_HPP +#define SHARE_GC_SERIAL_GENERATION_HPP #include "gc/shared/collectorCounters.hpp" #include "gc/shared/referenceProcessor.hpp" @@ -51,20 +51,10 @@ class DefNewGeneration; class GCMemoryManager; class ContiguousSpace; -class CompactPoint; + class OopClosure; class GCStats; -// A "ScratchBlock" represents a block of memory in one generation usable by -// another. It represents "num_words" free words, starting at and including -// the address of "this". -struct ScratchBlock { - ScratchBlock* next; - size_t num_words; - HeapWord scratch_space[1]; // Actually, of size "num_words-2" (assuming - // first two fields are word-sized.) -}; - class Generation: public CHeapObj { friend class VMStructs; private: @@ -175,10 +165,6 @@ class Generation: public CHeapObj { // Iteration - do not use for time critical operations virtual void space_iterate(SpaceClosure* blk, bool usedOnly = false) = 0; - // Returns the first space, if any, in the generation that can participate - // in compaction, or else "null". - virtual ContiguousSpace* first_compaction_space() const = 0; - // Returns "true" iff this generation should be used to allocate an // object of the given size. Young generations might // wish to exclude very large objects, for example, since, if allocated @@ -202,18 +188,6 @@ class Generation: public CHeapObj { // Thread-local allocation buffers virtual bool supports_tlab_allocation() const { return false; } - virtual size_t tlab_capacity() const { - guarantee(false, "Generation doesn't support thread local allocation buffers"); - return 0; - } - virtual size_t tlab_used() const { - guarantee(false, "Generation doesn't support thread local allocation buffers"); - return 0; - } - virtual size_t unsafe_max_tlab_alloc() const { - guarantee(false, "Generation doesn't support thread local allocation buffers"); - return 0; - } // "obj" is the address of an object in a younger generation. Allocate space // for "obj" in the current (or some higher) generation, and copy "obj" into @@ -228,7 +202,7 @@ class Generation: public CHeapObj { // this generation. See comment below. // This is a generic implementation which can be overridden. // - // Note: in the current (1.4) implementation, when genCollectedHeap's + // Note: in the current (1.4) implementation, when serialHeap's // incremental_collection_will_fail flag is set, all allocations are // slow path (the only fast-path place to allocate is DefNew, which // will be full if the flag is set). @@ -240,16 +214,6 @@ class Generation: public CHeapObj { return (full || should_allocate(word_size, is_tlab)); } - // Returns true if the collection is likely to be safely - // completed. Even if this method returns true, a collection - // may not be guaranteed to succeed, and the system should be - // able to safely unwind and recover from that failure, albeit - // at some additional cost. - virtual bool collection_attempt_is_safe() { - guarantee(false, "Are you sure you want to call this method?"); - return true; - } - // Perform a garbage collection. // If full is true attempt a full garbage collection of this generation. // Otherwise, attempting to (at least) free enough space to support an @@ -286,13 +250,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 9361a4e5eb961..b65bab44946e2 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,26 +23,82 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" +#include "code/icBuffer.hpp" +#include "compiler/oopMap.hpp" +#include "gc/serial/cardTableRS.hpp" #include "gc/serial/defNewGeneration.inline.hpp" +#include "gc/serial/genMarkSweep.hpp" +#include "gc/serial/markSweep.hpp" #include "gc/serial/serialHeap.hpp" +#include "gc/serial/serialMemoryPools.hpp" +#include "gc/serial/serialVMOperations.hpp" #include "gc/serial/tenuredGeneration.inline.hpp" +#include "gc/shared/cardTableBarrierSet.hpp" +#include "gc/shared/classUnloadingContext.hpp" +#include "gc/shared/collectedHeap.inline.hpp" +#include "gc/shared/collectorCounters.hpp" +#include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/gcId.hpp" +#include "gc/shared/gcInitLogger.hpp" #include "gc/shared/gcLocker.inline.hpp" -#include "gc/shared/genMemoryPools.hpp" +#include "gc/shared/gcPolicyCounters.hpp" +#include "gc/shared/gcTrace.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/gcVMOperations.hpp" +#include "gc/shared/genArguments.hpp" +#include "gc/shared/locationPrinter.inline.hpp" +#include "gc/shared/oopStorage.inline.hpp" +#include "gc/shared/oopStorageParState.inline.hpp" +#include "gc/shared/oopStorageSet.inline.hpp" #include "gc/shared/scavengableNMethods.hpp" +#include "gc/shared/space.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/shared/weakProcessor.hpp" +#include "gc/shared/workerThread.hpp" +#include "memory/iterator.hpp" +#include "memory/metaspaceCounters.hpp" +#include "memory/metaspaceUtils.hpp" +#include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/handles.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/threads.hpp" +#include "runtime/vmThread.hpp" #include "services/memoryManager.hpp" +#include "services/memoryService.hpp" +#include "utilities/autoRestore.hpp" +#include "utilities/debug.hpp" +#include "utilities/formatBuffer.hpp" +#include "utilities/macros.hpp" +#include "utilities/stack.inline.hpp" +#include "utilities/vmError.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif SerialHeap* SerialHeap::heap() { return named_heap(CollectedHeap::Serial); } SerialHeap::SerialHeap() : - GenCollectedHeap(Generation::DefNew, - Generation::MarkSweepCompact, - "Copy:MSC"), + CollectedHeap(), + _young_gen(nullptr), + _old_gen(nullptr), + _rem_set(nullptr), + _soft_ref_policy(), + _gc_policy_counters(new GCPolicyCounters("Copy:MSC", 2, 2)), + _incremental_collection_failed(false), + _young_manager(nullptr), + _old_manager(nullptr), _eden_pool(nullptr), _survivor_pool(nullptr), _old_pool(nullptr) { @@ -51,7 +107,6 @@ SerialHeap::SerialHeap() : } void SerialHeap::initialize_serviceability() { - DefNewGeneration* young = young_gen(); // Add a memory pool for each space and young gen doesn't @@ -75,7 +130,6 @@ void SerialHeap::initialize_serviceability() { _old_manager->add_pool(_survivor_pool); _old_manager->add_pool(_old_pool); old->set_gc_manager(_old_manager); - } GrowableArray SerialHeap::memory_managers() { @@ -133,3 +187,928 @@ void SerialHeap::pin_object(JavaThread* thread, oop obj) { void SerialHeap::unpin_object(JavaThread* thread, oop obj) { GCLocker::unlock_critical(thread); } + +jint SerialHeap::initialize() { + // Allocate space for the heap. + + ReservedHeapSpace heap_rs = allocate(HeapAlignment); + + if (!heap_rs.is_reserved()) { + vm_shutdown_during_initialization( + "Could not reserve enough space for object heap"); + return JNI_ENOMEM; + } + + initialize_reserved_region(heap_rs); + + ReservedSpace young_rs = heap_rs.first_part(MaxNewSize); + ReservedSpace old_rs = heap_rs.last_part(MaxNewSize); + + _rem_set = create_rem_set(heap_rs.region()); + _rem_set->initialize(young_rs.base(), old_rs.base()); + + CardTableBarrierSet *bs = new CardTableBarrierSet(_rem_set); + bs->initialize(); + BarrierSet::set_barrier_set(bs); + + _young_gen = new DefNewGeneration(young_rs, NewSize, MinNewSize, MaxNewSize); + _old_gen = new TenuredGeneration(old_rs, OldSize, MinOldSize, MaxOldSize, rem_set()); + + GCInitLogger::print(); + + return JNI_OK; +} + + +CardTableRS* SerialHeap::create_rem_set(const MemRegion& reserved_region) { + return new CardTableRS(reserved_region); +} + +ReservedHeapSpace SerialHeap::allocate(size_t alignment) { + // Now figure out the total size. + const size_t pageSize = UseLargePages ? os::large_page_size() : os::vm_page_size(); + assert(alignment % pageSize == 0, "Must be"); + + // Check for overflow. + size_t total_reserved = MaxNewSize + MaxOldSize; + if (total_reserved < MaxNewSize) { + vm_exit_during_initialization("The size of the object heap + VM data exceeds " + "the maximum representable size"); + } + assert(total_reserved % alignment == 0, + "Gen size; total_reserved=" SIZE_FORMAT ", alignment=" + SIZE_FORMAT, total_reserved, alignment); + + ReservedHeapSpace heap_rs = Universe::reserve_heap(total_reserved, alignment); + size_t used_page_size = heap_rs.page_size(); + + os::trace_page_sizes("Heap", + MinHeapSize, + total_reserved, + heap_rs.base(), + heap_rs.size(), + used_page_size); + + return heap_rs; +} + +class GenIsScavengable : public BoolObjectClosure { +public: + bool do_object_b(oop obj) { + return SerialHeap::heap()->is_in_young(obj); + } +}; + +static GenIsScavengable _is_scavengable; + +void SerialHeap::post_initialize() { + CollectedHeap::post_initialize(); + + DefNewGeneration* def_new_gen = (DefNewGeneration*)_young_gen; + + def_new_gen->ref_processor_init(); + + MarkSweep::initialize(); + + ScavengableNMethods::initialize(&_is_scavengable); +} + +PreGenGCValues SerialHeap::get_pre_gc_values() const { + const DefNewGeneration* const def_new_gen = (DefNewGeneration*) young_gen(); + + return PreGenGCValues(def_new_gen->used(), + def_new_gen->capacity(), + def_new_gen->eden()->used(), + def_new_gen->eden()->capacity(), + def_new_gen->from()->used(), + def_new_gen->from()->capacity(), + old_gen()->used(), + old_gen()->capacity()); +} + +size_t SerialHeap::capacity() const { + return _young_gen->capacity() + _old_gen->capacity(); +} + +size_t SerialHeap::used() const { + return _young_gen->used() + _old_gen->used(); +} + +void SerialHeap::save_used_regions() { + _old_gen->save_used_region(); + _young_gen->save_used_region(); +} + +size_t SerialHeap::max_capacity() const { + return _young_gen->max_capacity() + _old_gen->max_capacity(); +} + +// Return true if any of the following is true: +// . the allocation won't fit into the current young gen heap +// . gc locker is occupied (jni critical section) +// . heap memory is tight -- the most recent previous collection +// was a full collection because a partial collection (would +// have) failed and is likely to fail again +bool SerialHeap::should_try_older_generation_allocation(size_t word_size) const { + size_t young_capacity = _young_gen->capacity_before_gc(); + return (word_size > heap_word_size(young_capacity)) + || GCLocker::is_active_and_needs_gc() + || incremental_collection_failed(); +} + +HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { + HeapWord* result = nullptr; + if (_old_gen->should_allocate(size, is_tlab)) { + result = _old_gen->expand_and_allocate(size, is_tlab); + } + if (result == nullptr) { + if (_young_gen->should_allocate(size, is_tlab)) { + result = _young_gen->expand_and_allocate(size, is_tlab); + } + } + assert(result == nullptr || is_in_reserved(result), "result not in heap"); + return result; +} + +HeapWord* SerialHeap::mem_allocate_work(size_t size, + bool is_tlab) { + + HeapWord* result = nullptr; + + // Loop until the allocation is satisfied, or unsatisfied after GC. + for (uint try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { + + // First allocation attempt is lock-free. + Generation *young = _young_gen; + if (young->should_allocate(size, is_tlab)) { + result = young->par_allocate(size, is_tlab); + if (result != nullptr) { + assert(is_in_reserved(result), "result not in heap"); + return result; + } + } + uint gc_count_before; // Read inside the Heap_lock locked region. + { + MutexLocker ml(Heap_lock); + log_trace(gc, alloc)("SerialHeap::mem_allocate_work: attempting locked slow path allocation"); + // Note that only large objects get a shot at being + // allocated in later generations. + bool first_only = !should_try_older_generation_allocation(size); + + result = attempt_allocation(size, is_tlab, first_only); + if (result != nullptr) { + assert(is_in_reserved(result), "result not in heap"); + return result; + } + + if (GCLocker::is_active_and_needs_gc()) { + if (is_tlab) { + return nullptr; // Caller will retry allocating individual object. + } + if (!is_maximal_no_gc()) { + // Try and expand heap to satisfy request. + result = expand_heap_and_allocate(size, is_tlab); + // Result could be null if we are out of space. + if (result != nullptr) { + return result; + } + } + + if (gclocker_stalled_count > GCLockerRetryAllocationCount) { + return nullptr; // We didn't get to do a GC and we didn't get any memory. + } + + // If this thread is not in a jni critical section, we stall + // the requestor until the critical section has cleared and + // GC allowed. When the critical section clears, a GC is + // initiated by the last thread exiting the critical section; so + // we retry the allocation sequence from the beginning of the loop, + // rather than causing more, now probably unnecessary, GC attempts. + JavaThread* jthr = JavaThread::current(); + if (!jthr->in_critical()) { + MutexUnlocker mul(Heap_lock); + // Wait for JNI critical section to be exited + GCLocker::stall_until_clear(); + gclocker_stalled_count += 1; + continue; + } else { + if (CheckJNICalls) { + fatal("Possible deadlock due to allocating while" + " in jni critical section"); + } + return nullptr; + } + } + + // Read the gc count while the heap lock is held. + gc_count_before = total_collections(); + } + + VM_GenCollectForAllocation op(size, is_tlab, gc_count_before); + VMThread::execute(&op); + if (op.prologue_succeeded()) { + result = op.result(); + if (op.gc_locked()) { + assert(result == nullptr, "must be null if gc_locked() is true"); + continue; // Retry and/or stall as necessary. + } + + assert(result == nullptr || is_in_reserved(result), + "result not in heap"); + return result; + } + + // Give a warning if we seem to be looping forever. + if ((QueuedAllocationWarningCount > 0) && + (try_count % QueuedAllocationWarningCount == 0)) { + log_warning(gc, ergo)("SerialHeap::mem_allocate_work retries %d times," + " size=" SIZE_FORMAT " %s", try_count, size, is_tlab ? "(TLAB)" : ""); + } + } +} + +HeapWord* SerialHeap::attempt_allocation(size_t size, + bool is_tlab, + bool first_only) { + HeapWord* res = nullptr; + + if (_young_gen->should_allocate(size, is_tlab)) { + res = _young_gen->allocate(size, is_tlab); + if (res != nullptr || first_only) { + return res; + } + } + + if (_old_gen->should_allocate(size, is_tlab)) { + res = _old_gen->allocate(size, is_tlab); + } + + return res; +} + +HeapWord* SerialHeap::mem_allocate(size_t size, + bool* gc_overhead_limit_was_exceeded) { + return mem_allocate_work(size, + false /* is_tlab */); +} + +bool SerialHeap::must_clear_all_soft_refs() { + return _gc_cause == GCCause::_metadata_GC_clear_soft_refs || + _gc_cause == GCCause::_wb_full_gc; +} + +void SerialHeap::collect_generation(Generation* gen, bool full, size_t size, + bool is_tlab, bool run_verification, bool clear_soft_refs) { + FormatBuffer<> title("Collect gen: %s", gen->short_name()); + GCTraceTime(Trace, gc, phases) t1(title); + TraceCollectorStats tcs(gen->counters()); + TraceMemoryManagerStats tmms(gen->gc_manager(), gc_cause(), heap()->is_young_gen(gen) ? "end of minor GC" : "end of major GC"); + + gen->stat_record()->invocations++; + gen->stat_record()->accumulated_time.start(); + + // Must be done anew before each collection because + // a previous collection will do mangling and will + // change top of some spaces. + record_gen_tops_before_GC(); + + log_trace(gc)("%s invoke=%d size=" SIZE_FORMAT, heap()->is_young_gen(gen) ? "Young" : "Old", gen->stat_record()->invocations, size * HeapWordSize); + + if (run_verification && VerifyBeforeGC) { + Universe::verify("Before GC"); + } + COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::clear()); + + // Do collection work + { + save_marks(); // save marks for all gens + + gen->collect(full, clear_soft_refs, size, is_tlab); + } + + COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::update_pointers()); + + gen->stat_record()->accumulated_time.stop(); + + update_gc_stats(gen, full); + + if (run_verification && VerifyAfterGC) { + Universe::verify("After GC"); + } +} + +void SerialHeap::do_collection(bool full, + bool clear_all_soft_refs, + size_t size, + bool is_tlab, + GenerationType max_generation) { + ResourceMark rm; + DEBUG_ONLY(Thread* my_thread = Thread::current();) + + assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); + assert(my_thread->is_VM_thread(), "only VM thread"); + assert(Heap_lock->is_locked(), + "the requesting thread should have the Heap_lock"); + guarantee(!is_gc_active(), "collection is not reentrant"); + + if (GCLocker::check_active_before_gc()) { + return; // GC is disabled (e.g. JNI GetXXXCritical operation) + } + + const bool do_clear_all_soft_refs = clear_all_soft_refs || + soft_ref_policy()->should_clear_all_soft_refs(); + + ClearedAllSoftRefs casr(do_clear_all_soft_refs, soft_ref_policy()); + + AutoModifyRestore temporarily(_is_gc_active, true); + + bool complete = full && (max_generation == OldGen); + bool old_collects_young = complete && !ScavengeBeforeFullGC; + bool do_young_collection = !old_collects_young && _young_gen->should_collect(full, size, is_tlab); + + const PreGenGCValues pre_gc_values = get_pre_gc_values(); + + bool run_verification = total_collections() >= VerifyGCStartAt; + bool prepared_for_verification = false; + bool do_full_collection = false; + + if (do_young_collection) { + GCIdMark gc_id_mark; + GCTraceCPUTime tcpu(((DefNewGeneration*)_young_gen)->gc_tracer()); + GCTraceTime(Info, gc) t("Pause Young", nullptr, gc_cause(), true); + + print_heap_before_gc(); + + if (run_verification && VerifyGCLevel <= 0 && VerifyBeforeGC) { + prepare_for_verify(); + prepared_for_verification = true; + } + + gc_prologue(complete); + increment_total_collections(complete); + + collect_generation(_young_gen, + full, + size, + is_tlab, + run_verification && VerifyGCLevel <= 0, + do_clear_all_soft_refs); + + if (size > 0 && (!is_tlab || _young_gen->supports_tlab_allocation()) && + size * HeapWordSize <= _young_gen->unsafe_max_alloc_nogc()) { + // Allocation request was met by young GC. + size = 0; + } + + // Ask if young collection is enough. If so, do the final steps for young collection, + // and fallthrough to the end. + do_full_collection = should_do_full_collection(size, full, is_tlab, max_generation); + if (!do_full_collection) { + // Adjust generation sizes. + _young_gen->compute_new_size(); + + print_heap_change(pre_gc_values); + + // Track memory usage and detect low memory after GC finishes + MemoryService::track_memory_usage(); + + gc_epilogue(complete); + } + + print_heap_after_gc(); + + } else { + // No young collection, ask if we need to perform Full collection. + do_full_collection = should_do_full_collection(size, full, is_tlab, max_generation); + } + + if (do_full_collection) { + GCIdMark gc_id_mark; + GCTraceCPUTime tcpu(GenMarkSweep::gc_tracer()); + GCTraceTime(Info, gc) t("Pause Full", nullptr, gc_cause(), true); + + print_heap_before_gc(); + + if (!prepared_for_verification && run_verification && + VerifyGCLevel <= 1 && VerifyBeforeGC) { + prepare_for_verify(); + } + + if (!do_young_collection) { + gc_prologue(complete); + increment_total_collections(complete); + } + + // Accounting quirk: total full collections would be incremented when "complete" + // is set, by calling increment_total_collections above. However, we also need to + // account Full collections that had "complete" unset. + if (!complete) { + increment_total_full_collections(); + } + + 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, + full, + size, + is_tlab, + run_verification && VerifyGCLevel <= 1, + do_clear_all_soft_refs); + + CodeCache::on_gc_marking_cycle_finish(); + CodeCache::arm_all_nmethods(); + + // Adjust generation sizes. + _old_gen->compute_new_size(); + _young_gen->compute_new_size(); + + // Delete metaspaces for unloaded class loaders and clean up loader_data graph + ClassLoaderDataGraph::purge(/*at_safepoint*/true); + DEBUG_ONLY(MetaspaceUtils::verify();) + + // Need to clear claim bits for the next mark. + ClassLoaderDataGraph::clear_claimed_marks(); + + // Resize the metaspace capacity after full collections + MetaspaceGC::compute_new_size(); + + print_heap_change(pre_gc_values); + + // Track memory usage and detect low memory after GC finishes + MemoryService::track_memory_usage(); + + // Need to tell the epilogue code we are done with Full GC, regardless what was + // the initial value for "complete" flag. + gc_epilogue(true); + + print_heap_after_gc(); + } +} + +bool SerialHeap::should_do_full_collection(size_t size, bool full, bool is_tlab, + SerialHeap::GenerationType max_gen) const { + return max_gen == OldGen && _old_gen->should_collect(full, size, is_tlab); +} + +void SerialHeap::register_nmethod(nmethod* nm) { + ScavengableNMethods::register_nmethod(nm); +} + +void SerialHeap::unregister_nmethod(nmethod* nm) { + ScavengableNMethods::unregister_nmethod(nm); +} + +void SerialHeap::verify_nmethod(nmethod* nm) { + ScavengableNMethods::verify_nmethod(nm); +} + +void SerialHeap::prune_scavengable_nmethods() { + ScavengableNMethods::prune_nmethods_not_into_young(); +} + +void SerialHeap::prune_unlinked_nmethods() { + ScavengableNMethods::prune_unlinked_nmethods(); +} + +HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { + GCCauseSetter x(this, GCCause::_allocation_failure); + HeapWord* result = nullptr; + + assert(size != 0, "Precondition violated"); + if (GCLocker::is_active_and_needs_gc()) { + // GC locker is active; instead of a collection we will attempt + // to expand the heap, if there's room for expansion. + if (!is_maximal_no_gc()) { + result = expand_heap_and_allocate(size, is_tlab); + } + return result; // Could be null if we are out of space. + } else if (!incremental_collection_will_fail(false /* don't consult_young */)) { + // Do an incremental collection. + do_collection(false, // full + false, // clear_all_soft_refs + size, // size + is_tlab, // is_tlab + SerialHeap::OldGen); // max_generation + } else { + log_trace(gc)(" :: Trying full because partial may fail :: "); + // Try a full collection; see delta for bug id 6266275 + // for the original code and why this has been simplified + // with from-space allocation criteria modified and + // such allocation moved out of the safepoint path. + do_collection(true, // full + false, // clear_all_soft_refs + size, // size + is_tlab, // is_tlab + SerialHeap::OldGen); // max_generation + } + + result = attempt_allocation(size, is_tlab, false /*first_only*/); + + if (result != nullptr) { + assert(is_in_reserved(result), "result not in heap"); + return result; + } + + // OK, collection failed, try expansion. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } + + // If we reach this point, we're really out of memory. Try every trick + // we can to reclaim memory. Force collection of soft references. Force + // a complete compaction of the heap. Any additional methods for finding + // free memory should be here, especially if they are expensive. If this + // attempt fails, an OOM exception will be thrown. + { + UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted + + do_collection(true, // full + true, // clear_all_soft_refs + size, // size + is_tlab, // is_tlab + SerialHeap::OldGen); // max_generation + } + + result = attempt_allocation(size, is_tlab, false /* first_only */); + if (result != nullptr) { + assert(is_in_reserved(result), "result not in heap"); + return result; + } + + assert(!soft_ref_policy()->should_clear_all_soft_refs(), + "Flag should have been handled and cleared prior to this point"); + + // What else? We might try synchronous finalization later. If the total + // space available is large enough for the allocation, then a more + // complete compaction phase than we've tried so far might be + // appropriate. + return nullptr; +} + +#ifdef ASSERT +class AssertNonScavengableClosure: public OopClosure { +public: + virtual void do_oop(oop* p) { + assert(!SerialHeap::heap()->is_in_partial_collection(*p), + "Referent should not be scavengable."); } + virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } +}; +static AssertNonScavengableClosure assert_is_non_scavengable_closure; +#endif + +void SerialHeap::process_roots(ScanningOption so, + OopClosure* strong_roots, + CLDClosure* strong_cld_closure, + CLDClosure* weak_cld_closure, + CodeBlobToOopClosure* code_roots) { + // General roots. + assert(code_roots != nullptr, "code root closure should always be set"); + + ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure); + + // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway + CodeBlobToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? nullptr : code_roots; + + Threads::oops_do(strong_roots, roots_from_code_p); + + OopStorageSet::strong_oops_do(strong_roots); + + if (so & SO_ScavengeCodeCache) { + assert(code_roots != nullptr, "must supply closure for code cache"); + + // We only visit parts of the CodeCache when scavenging. + ScavengableNMethods::nmethods_do(code_roots); + } + if (so & SO_AllCodeCache) { + assert(code_roots != nullptr, "must supply closure for code cache"); + + // CMSCollector uses this to do intermediate-strength collections. + // We scan the entire code cache, since CodeCache::do_unloading is not called. + CodeCache::blobs_do(code_roots); + } + // Verify that the code cache contents are not subject to + // movement by a scavenging collection. + DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations)); + DEBUG_ONLY(ScavengableNMethods::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); +} + +bool SerialHeap::no_allocs_since_save_marks() { + return _young_gen->no_allocs_since_save_marks() && + _old_gen->no_allocs_since_save_marks(); +} + +// public collection interfaces +void SerialHeap::collect(GCCause::Cause cause) { + // The caller doesn't have the Heap_lock + assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); + + unsigned int gc_count_before; + unsigned int full_gc_count_before; + + { + MutexLocker ml(Heap_lock); + // Read the GC count while holding the Heap_lock + gc_count_before = total_collections(); + full_gc_count_before = total_full_collections(); + } + + if (GCLocker::should_discard(cause, gc_count_before)) { + return; + } + + bool should_run_young_gc = (cause == GCCause::_wb_young_gc) + || (cause == GCCause::_gc_locker) + DEBUG_ONLY(|| (cause == GCCause::_scavenge_alot)); + + const GenerationType max_generation = should_run_young_gc + ? YoungGen + : OldGen; + + while (true) { + VM_GenCollectFull op(gc_count_before, full_gc_count_before, + cause, max_generation); + VMThread::execute(&op); + + if (!GCCause::is_explicit_full_gc(cause)) { + return; + } + + { + MutexLocker ml(Heap_lock); + // Read the GC count while holding the Heap_lock + if (full_gc_count_before != total_full_collections()) { + return; + } + } + + if (GCLocker::is_active_and_needs_gc()) { + // If GCLocker is active, wait until clear before retrying. + GCLocker::stall_until_clear(); + } + } +} + +void SerialHeap::do_full_collection(bool clear_all_soft_refs) { + do_full_collection(clear_all_soft_refs, OldGen); +} + +void SerialHeap::do_full_collection(bool clear_all_soft_refs, + GenerationType last_generation) { + do_collection(true, // full + clear_all_soft_refs, // clear_all_soft_refs + 0, // size + false, // is_tlab + last_generation); // last_generation + // Hack XXX FIX ME !!! + // A scavenge may not have been attempted, or may have + // been attempted and failed, because the old gen was too full + if (gc_cause() == GCCause::_gc_locker && incremental_collection_failed()) { + log_debug(gc, jni)("GC locker: Trying a full collection because scavenge failed"); + // This time allow the old gen to be collected as well + do_collection(true, // full + clear_all_soft_refs, // clear_all_soft_refs + 0, // size + false, // is_tlab + OldGen); // last_generation + } +} + +bool SerialHeap::is_in_young(const void* p) const { + bool result = p < _old_gen->reserved().start(); + assert(result == _young_gen->is_in_reserved(p), + "incorrect test - result=%d, p=" PTR_FORMAT, result, p2i(p)); + return result; +} + +bool SerialHeap::requires_barriers(stackChunkOop obj) const { + return !is_in_young(obj); +} + +// Returns "TRUE" iff "p" points into the committed areas of the heap. +bool SerialHeap::is_in(const void* p) const { + return _young_gen->is_in(p) || _old_gen->is_in(p); +} + +#ifdef ASSERT +// Don't implement this by using is_in_young(). This method is used +// in some cases to check that is_in_young() is correct. +bool SerialHeap::is_in_partial_collection(const void* p) { + assert(is_in_reserved(p) || p == nullptr, + "Does not work if address is non-null and outside of the heap"); + return p < _young_gen->reserved().end() && p != nullptr; +} +#endif + +void SerialHeap::object_iterate(ObjectClosure* cl) { + _young_gen->object_iterate(cl); + _old_gen->object_iterate(cl); +} + +HeapWord* SerialHeap::block_start(const void* addr) const { + assert(is_in_reserved(addr), "block_start of address outside of heap"); + if (_young_gen->is_in_reserved(addr)) { + assert(_young_gen->is_in(addr), "addr should be in allocated part of generation"); + return _young_gen->block_start(addr); + } + + assert(_old_gen->is_in_reserved(addr), "Some generation should contain the address"); + assert(_old_gen->is_in(addr), "addr should be in allocated part of generation"); + return _old_gen->block_start(addr); +} + +bool SerialHeap::block_is_obj(const HeapWord* addr) const { + assert(is_in_reserved(addr), "block_is_obj of address outside of heap"); + assert(block_start(addr) == addr, "addr must be a block start"); + if (_young_gen->is_in_reserved(addr)) { + return _young_gen->block_is_obj(addr); + } + + assert(_old_gen->is_in_reserved(addr), "Some generation should contain the address"); + return _old_gen->block_is_obj(addr); +} + +size_t SerialHeap::tlab_capacity(Thread* thr) const { + assert(!_old_gen->supports_tlab_allocation(), "Old gen supports TLAB allocation?!"); + assert(_young_gen->supports_tlab_allocation(), "Young gen doesn't support TLAB allocation?!"); + return _young_gen->tlab_capacity(); +} + +size_t SerialHeap::tlab_used(Thread* thr) const { + assert(!_old_gen->supports_tlab_allocation(), "Old gen supports TLAB allocation?!"); + assert(_young_gen->supports_tlab_allocation(), "Young gen doesn't support TLAB allocation?!"); + return _young_gen->tlab_used(); +} + +size_t SerialHeap::unsafe_max_tlab_alloc(Thread* thr) const { + assert(!_old_gen->supports_tlab_allocation(), "Old gen supports TLAB allocation?!"); + assert(_young_gen->supports_tlab_allocation(), "Young gen doesn't support TLAB allocation?!"); + return _young_gen->unsafe_max_tlab_alloc(); +} + +HeapWord* SerialHeap::allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size) { + HeapWord* result = mem_allocate_work(requested_size /* size */, + true /* is_tlab */); + if (result != nullptr) { + *actual_size = requested_size; + } + + return result; +} + +void SerialHeap::prepare_for_verify() { + ensure_parsability(false); // no need to retire TLABs +} + +void SerialHeap::generation_iterate(GenClosure* cl, + bool old_to_young) { + if (old_to_young) { + cl->do_generation(_old_gen); + cl->do_generation(_young_gen); + } else { + cl->do_generation(_young_gen); + cl->do_generation(_old_gen); + } +} + +bool SerialHeap::is_maximal_no_gc() const { + return _young_gen->is_maximal_no_gc() && _old_gen->is_maximal_no_gc(); +} + +void SerialHeap::save_marks() { + _young_gen->save_marks(); + _old_gen->save_marks(); +} + +void SerialHeap::verify(VerifyOption option /* ignored */) { + log_debug(gc, verify)("%s", _old_gen->name()); + _old_gen->verify(); + + log_debug(gc, verify)("%s", _young_gen->name()); + _young_gen->verify(); + + log_debug(gc, verify)("RemSet"); + rem_set()->verify(); +} + +void SerialHeap::print_on(outputStream* st) const { + if (_young_gen != nullptr) { + _young_gen->print_on(st); + } + if (_old_gen != nullptr) { + _old_gen->print_on(st); + } + MetaspaceUtils::print_on(st); +} + +void SerialHeap::gc_threads_do(ThreadClosure* tc) const { +} + +bool SerialHeap::print_location(outputStream* st, void* addr) const { + return BlockLocationPrinter::print_location(st, addr); +} + +void SerialHeap::print_tracing_info() const { + if (log_is_enabled(Debug, gc, heap, exit)) { + LogStreamHandle(Debug, gc, heap, exit) lsh; + _young_gen->print_summary_info_on(&lsh); + _old_gen->print_summary_info_on(&lsh); + } +} + +void SerialHeap::print_heap_change(const PreGenGCValues& pre_gc_values) const { + const DefNewGeneration* const def_new_gen = (DefNewGeneration*) young_gen(); + + log_info(gc, heap)(HEAP_CHANGE_FORMAT" " + HEAP_CHANGE_FORMAT" " + HEAP_CHANGE_FORMAT, + HEAP_CHANGE_FORMAT_ARGS(def_new_gen->short_name(), + pre_gc_values.young_gen_used(), + pre_gc_values.young_gen_capacity(), + def_new_gen->used(), + def_new_gen->capacity()), + HEAP_CHANGE_FORMAT_ARGS("Eden", + pre_gc_values.eden_used(), + pre_gc_values.eden_capacity(), + def_new_gen->eden()->used(), + def_new_gen->eden()->capacity()), + HEAP_CHANGE_FORMAT_ARGS("From", + pre_gc_values.from_used(), + pre_gc_values.from_capacity(), + def_new_gen->from()->used(), + def_new_gen->from()->capacity())); + log_info(gc, heap)(HEAP_CHANGE_FORMAT, + HEAP_CHANGE_FORMAT_ARGS(old_gen()->short_name(), + pre_gc_values.old_gen_used(), + pre_gc_values.old_gen_capacity(), + old_gen()->used(), + old_gen()->capacity())); + MetaspaceUtils::print_metaspace_change(pre_gc_values.metaspace_sizes()); +} + +class GenGCPrologueClosure: public SerialHeap::GenClosure { + private: + bool _full; + public: + void do_generation(Generation* gen) { + gen->gc_prologue(_full); + } + GenGCPrologueClosure(bool full) : _full(full) {}; +}; + +void SerialHeap::gc_prologue(bool full) { + assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); + + // Fill TLAB's and such + ensure_parsability(true); // retire TLABs + + // Walk generations + GenGCPrologueClosure blk(full); + generation_iterate(&blk, false); // not old-to-young. +}; + +class GenGCEpilogueClosure: public SerialHeap::GenClosure { + private: + bool _full; + public: + void do_generation(Generation* gen) { + gen->gc_epilogue(_full); + } + GenGCEpilogueClosure(bool full) : _full(full) {}; +}; + +void SerialHeap::gc_epilogue(bool full) { +#if COMPILER2_OR_JVMCI + assert(DerivedPointerTable::is_empty(), "derived pointer present"); +#endif // COMPILER2_OR_JVMCI + + resize_all_tlabs(); + + GenGCEpilogueClosure blk(full); + generation_iterate(&blk, false); // not old-to-young. + + MetaspaceCounters::update_performance_counters(); +}; + +#ifndef PRODUCT +class GenGCSaveTopsBeforeGCClosure: public SerialHeap::GenClosure { + private: + public: + void do_generation(Generation* gen) { + gen->record_spaces_top(); + } +}; + +void SerialHeap::record_gen_tops_before_GC() { + if (ZapUnusedHeapArea) { + GenGCSaveTopsBeforeGCClosure blk; + generation_iterate(&blk, false); // not old-to-young. + } +} +#endif // not PRODUCT diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index da86f2909d78e..71880e7c7712e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,17 @@ #define SHARE_GC_SERIAL_SERIALHEAP_HPP #include "gc/serial/defNewGeneration.hpp" +#include "gc/serial/generation.hpp" #include "gc/serial/tenuredGeneration.hpp" -#include "gc/shared/genCollectedHeap.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/oopStorageParState.hpp" +#include "gc/shared/preGCValues.hpp" +#include "gc/shared/softRefPolicy.hpp" #include "utilities/growableArray.hpp" +class CardTableRS; +class GCPolicyCounters; + class GCMemoryManager; class MemoryPool; class OopIterateClosure; @@ -55,7 +62,284 @@ class TenuredGeneration; // +-----------------+--------+--------+--------+---------------+-------------------+ // |<- committed ->| |<- committed ->| // -class SerialHeap : public GenCollectedHeap { +class SerialHeap : public CollectedHeap { + friend class Generation; + friend class DefNewGeneration; + friend class TenuredGeneration; + friend class GenMarkSweep; + friend class VM_GenCollectForAllocation; + friend class VM_GenCollectFull; + friend class VM_GC_HeapInspection; + friend class VM_HeapDumper; + friend class HeapInspection; + friend class GCCauseSetter; + friend class VMStructs; +public: + friend class VM_PopulateDumpSharedSpace; + + enum GenerationType { + YoungGen, + OldGen + }; + +private: + DefNewGeneration* _young_gen; + TenuredGeneration* _old_gen; + +private: + // The singleton CardTable Remembered Set. + CardTableRS* _rem_set; + + SoftRefPolicy _soft_ref_policy; + + GCPolicyCounters* _gc_policy_counters; + + // Indicates that the most recent previous incremental collection failed. + // The flag is cleared when an action is taken that might clear the + // condition that caused that incremental collection to fail. + bool _incremental_collection_failed; + + // Collects the given generation. + void collect_generation(Generation* gen, bool full, size_t size, bool is_tlab, + bool run_verification, bool clear_soft_refs); + + // Reserve aligned space for the heap as needed by the contained generations. + ReservedHeapSpace allocate(size_t alignment); + + PreGenGCValues get_pre_gc_values() const; + +private: + GCMemoryManager* _young_manager; + GCMemoryManager* _old_manager; + + // Helper functions for allocation + HeapWord* attempt_allocation(size_t size, + bool is_tlab, + bool first_only); + + // Helper function for two callbacks below. + // Considers collection of the first max_level+1 generations. + void do_collection(bool full, + bool clear_all_soft_refs, + size_t size, + bool is_tlab, + GenerationType max_generation); + + // Callback from VM_GenCollectForAllocation operation. + // This function does everything necessary/possible to satisfy an + // allocation request that failed in the youngest generation that should + // have handled it (including collection, expansion, etc.) + HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab); + + // Callback from VM_GenCollectFull operation. + // Perform a full collection of the first max_level+1 generations. + void do_full_collection(bool clear_all_soft_refs) override; + void do_full_collection(bool clear_all_soft_refs, GenerationType max_generation); + + // Does the "cause" of GC indicate that + // we absolutely __must__ clear soft refs? + bool must_clear_all_soft_refs(); + +public: + // Returns JNI_OK on success + jint initialize() override; + virtual CardTableRS* create_rem_set(const MemRegion& reserved_region); + + // Does operations required after initialization has been done. + void post_initialize() override; + + bool is_young_gen(const Generation* gen) const { return gen == _young_gen; } + bool is_old_gen(const Generation* gen) const { return gen == _old_gen; } + + MemRegion reserved_region() const { return _reserved; } + bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } + + SoftRefPolicy* soft_ref_policy() override { return &_soft_ref_policy; } + + // Performance Counter support + GCPolicyCounters* counters() { return _gc_policy_counters; } + + size_t capacity() const override; + size_t used() const override; + + // Save the "used_region" for both generations. + void save_used_regions(); + + size_t max_capacity() const override; + + HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + + // Perform a full collection of the heap; intended for use in implementing + // "System.gc". This implies as full a collection as the CollectedHeap + // supports. Caller does not hold the Heap_lock on entry. + void collect(GCCause::Cause cause) override; + + // Returns "TRUE" iff "p" points into the committed areas of the heap. + // The methods is_in() and is_in_youngest() may be expensive to compute + // in general, so, to prevent their inadvertent use in product jvm's, we + // restrict their use to assertion checking or verification only. + bool is_in(const void* p) const override; + + // Returns true if p points into the reserved space for the young generation. + // Assumes the young gen address range is less than that of the old gen. + bool is_in_young(const void* p) const; + + bool requires_barriers(stackChunkOop obj) const override; + +#ifdef ASSERT + bool is_in_partial_collection(const void* p); +#endif + + // Optimized nmethod scanning support routines + void register_nmethod(nmethod* nm) override; + void unregister_nmethod(nmethod* nm) override; + void verify_nmethod(nmethod* nm) override; + + void prune_scavengable_nmethods(); + void prune_unlinked_nmethods(); + + // Iteration functions. + void object_iterate(ObjectClosure* cl) override; + + // A CollectedHeap is divided into a dense sequence of "blocks"; that is, + // each address in the (reserved) heap is a member of exactly + // one block. The defining characteristic of a block is that it is + // possible to find its size, and thus to progress forward to the next + // block. (Blocks may be of different sizes.) Thus, blocks may + // represent Java objects, or they might be free blocks in a + // free-list-based heap (or subheap), as long as the two kinds are + // distinguishable and the size of each is determinable. + + // Returns the address of the start of the "block" that contains the + // address "addr". We say "blocks" instead of "object" since some heaps + // may not pack objects densely; a chunk may either be an object or a + // non-object. + HeapWord* block_start(const void* addr) const; + + // Requires "addr" to be the start of a block, and returns "TRUE" iff + // the block is an object. Assumes (and verifies in non-product + // builds) that addr is in the allocated part of the heap and is + // the start of a chunk. + bool block_is_obj(const HeapWord* addr) const; + + // Section on TLAB's. + size_t tlab_capacity(Thread* thr) const override; + size_t tlab_used(Thread* thr) const override; + size_t unsafe_max_tlab_alloc(Thread* thr) const override; + HeapWord* allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size) override; + + // Update the gc statistics for each generation. + void update_gc_stats(Generation* current_generation, bool full) { + _old_gen->update_gc_stats(current_generation, full); + } + + void prepare_for_verify() override; + void verify(VerifyOption option) override; + + void print_on(outputStream* st) const override; + void gc_threads_do(ThreadClosure* tc) const override; + void print_tracing_info() const override; + + // Used to print information about locations in the hs_err file. + bool print_location(outputStream* st, void* addr) const override; + + void print_heap_change(const PreGenGCValues& pre_gc_values) const; + + // The functions below are helper functions that a subclass of + // "CollectedHeap" can use in the implementation of its virtual + // functions. + + class GenClosure : public StackObj { + public: + virtual void do_generation(Generation* gen) = 0; + }; + + // Apply "cl.do_generation" to all generations in the heap + // If "old_to_young" determines the order. + void generation_iterate(GenClosure* cl, bool old_to_young); + + // Return "true" if all generations have reached the + // maximal committed limit that they can reach, without a garbage + // collection. + virtual bool is_maximal_no_gc() const override; + + // This function returns the CardTableRS object that allows us to scan + // generations in a fully generational heap. + CardTableRS* rem_set() { return _rem_set; } + + // The ScanningOption determines which of the roots + // the closure is applied to: + // "SO_None" does none; + enum ScanningOption { + SO_None = 0x0, + SO_AllCodeCache = 0x8, + SO_ScavengeCodeCache = 0x10 + }; + + protected: + virtual void gc_prologue(bool full); + virtual void gc_epilogue(bool full); + + public: + // Apply closures on various roots in Young GC or marking/adjust phases of Full GC. + void process_roots(ScanningOption so, + OopClosure* strong_roots, + CLDClosure* strong_cld_closure, + CLDClosure* weak_cld_closure, + CodeBlobToOopClosure* code_roots); + + // 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. + void save_marks(); + + // Returns "true" iff no allocations have occurred since the last + // call to "save_marks". + bool no_allocs_since_save_marks(); + + // Returns true if an incremental collection is likely to fail. + // We optionally consult the young gen, if asked to do so; + // otherwise we base our answer on whether the previous incremental + // collection attempt failed with no corrective action as of yet. + bool incremental_collection_will_fail(bool consult_young) { + // The first disjunct remembers if an incremental collection failed, even + // when we thought (second disjunct) that it would not. + return incremental_collection_failed() || + (consult_young && !_young_gen->collection_attempt_is_safe()); + } + + // If a generation bails out of an incremental collection, + // it sets this flag. + bool incremental_collection_failed() const { + return _incremental_collection_failed; + } + void set_incremental_collection_failed() { + _incremental_collection_failed = true; + } + void clear_incremental_collection_failed() { + _incremental_collection_failed = false; + } + +private: + // Return true if an allocation should be attempted in the older generation + // if it fails in the younger generation. Return false, otherwise. + bool should_try_older_generation_allocation(size_t word_size) const; + + // Try to allocate space by expanding the heap. + HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); + + HeapWord* mem_allocate_work(size_t size, + bool is_tlab); + + // Save the tops of the spaces in all generations + void record_gen_tops_before_GC() PRODUCT_RETURN; + + // Return true if we need to perform full collection. + bool should_do_full_collection(size_t size, bool full, + bool is_tlab, GenerationType max_gen) const; + private: MemoryPool* _eden_pool; MemoryPool* _survivor_pool; diff --git a/src/hotspot/share/gc/shared/genMemoryPools.cpp b/src/hotspot/share/gc/serial/serialMemoryPools.cpp similarity index 94% rename from src/hotspot/share/gc/shared/genMemoryPools.cpp rename to src/hotspot/share/gc/serial/serialMemoryPools.cpp index 9158e42a1b9d8..f688771f60912 100644 --- a/src/hotspot/share/gc/shared/genMemoryPools.cpp +++ b/src/hotspot/share/gc/serial/serialMemoryPools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,10 @@ */ #include "precompiled.hpp" +#include "gc/serial/defNewGeneration.hpp" #include "gc/serial/generation.hpp" -#include "gc/shared/genMemoryPools.hpp" +#include "gc/serial/serialMemoryPools.hpp" #include "gc/shared/space.hpp" -#if INCLUDE_SERIALGC -#include "gc/serial/defNewGeneration.hpp" -#endif ContiguousSpacePool::ContiguousSpacePool(ContiguousSpace* space, const char* name, @@ -50,8 +48,6 @@ MemoryUsage ContiguousSpacePool::get_memory_usage() { return MemoryUsage(initial_size(), used, committed, maxSize); } -#if INCLUDE_SERIALGC - SurvivorContiguousSpacePool::SurvivorContiguousSpacePool(DefNewGeneration* young_gen, const char* name, size_t max_size, @@ -76,8 +72,6 @@ MemoryUsage SurvivorContiguousSpacePool::get_memory_usage() { return MemoryUsage(initial_size(), used, committed, maxSize); } -#endif // INCLUDE_SERIALGC - GenerationPool::GenerationPool(Generation* gen, const char* name, bool support_usage_threshold) : diff --git a/src/hotspot/share/gc/shared/genMemoryPools.hpp b/src/hotspot/share/gc/serial/serialMemoryPools.hpp similarity index 91% rename from src/hotspot/share/gc/shared/genMemoryPools.hpp rename to src/hotspot/share/gc/serial/serialMemoryPools.hpp index 27ee5c978228d..aa89e4e4c382e 100644 --- a/src/hotspot/share/gc/shared/genMemoryPools.hpp +++ b/src/hotspot/share/gc/serial/serialMemoryPools.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_GC_SHARED_GENMEMORYPOOLS_HPP -#define SHARE_GC_SHARED_GENMEMORYPOOLS_HPP +#ifndef SHARE_GC_SERIAL_SERIALMEMORYPOOLS_HPP +#define SHARE_GC_SERIAL_SERIALMEMORYPOOLS_HPP #include "services/memoryPool.hpp" @@ -72,4 +72,4 @@ class GenerationPool : public CollectedMemoryPool { size_t used_in_bytes(); }; -#endif // SHARE_GC_SHARED_GENMEMORYPOOLS_HPP +#endif // SHARE_GC_SERIAL_SERIALMEMORYPOOLS_HPP diff --git a/src/hotspot/share/gc/serial/serialVMOperations.cpp b/src/hotspot/share/gc/serial/serialVMOperations.cpp new file mode 100644 index 0000000000000..9e88fa5971196 --- /dev/null +++ b/src/hotspot/share/gc/serial/serialVMOperations.cpp @@ -0,0 +1,48 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc/serial/serialVMOperations.hpp" +#include "gc/shared/gcLocker.hpp" + +void VM_GenCollectForAllocation::doit() { + SvcGCMarker sgcm(SvcGCMarker::MINOR); + + SerialHeap* gch = SerialHeap::heap(); + GCCauseSetter gccs(gch, _gc_cause); + _result = gch->satisfy_failed_allocation(_word_size, _tlab); + assert(_result == nullptr || gch->is_in_reserved(_result), "result not in heap"); + + if (_result == nullptr && GCLocker::is_active_and_needs_gc()) { + set_gc_locked(); + } +} + +void VM_GenCollectFull::doit() { + SvcGCMarker sgcm(SvcGCMarker::FULL); + + SerialHeap* gch = SerialHeap::heap(); + GCCauseSetter gccs(gch, _gc_cause); + gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_generation); +} diff --git a/src/hotspot/share/gc/serial/serialVMOperations.hpp b/src/hotspot/share/gc/serial/serialVMOperations.hpp new file mode 100644 index 0000000000000..a056740dd8549 --- /dev/null +++ b/src/hotspot/share/gc/serial/serialVMOperations.hpp @@ -0,0 +1,66 @@ +/* + * 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. + * + */ + +#ifndef SHARE_GC_SERIAL_SERIALVMOPERATIONS_HPP +#define SHARE_GC_SERIAL_SERIALVMOPERATIONS_HPP + +#include "gc/serial/serialHeap.hpp" +#include "gc/shared/gcVMOperations.hpp" + +class VM_GenCollectForAllocation : public VM_CollectForAllocation { + private: + bool _tlab; // alloc is of a tlab. + public: + VM_GenCollectForAllocation(size_t word_size, + bool tlab, + uint gc_count_before) + : VM_CollectForAllocation(word_size, gc_count_before, GCCause::_allocation_failure), + _tlab(tlab) { + assert(word_size != 0, "An allocation should always be requested with this operation."); + } + ~VM_GenCollectForAllocation() {} + virtual VMOp_Type type() const { return VMOp_GenCollectForAllocation; } + virtual void doit(); +}; + +// VM operation to invoke a collection of the heap as a +// SerialHeap heap. +class VM_GenCollectFull: public VM_GC_Operation { + private: + SerialHeap::GenerationType _max_generation; + public: + VM_GenCollectFull(uint gc_count_before, + uint full_gc_count_before, + GCCause::Cause gc_cause, + SerialHeap::GenerationType max_generation) + : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, + max_generation != SerialHeap::YoungGen /* full */), + _max_generation(max_generation) { } + ~VM_GenCollectFull() {} + virtual VMOp_Type type() const { return VMOp_GenCollectFull; } + virtual void doit(); +}; + + +#endif // SHARE_GC_SERIAL_SERIALVMOPERATIONS_HPP diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 75e8bf8486051..7c0cd2ffd7b34 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. @@ -101,8 +101,6 @@ class TenuredGeneration: public Generation { bool is_in(const void* p) const; - ContiguousSpace* first_compaction_space() const; - TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, size_t min_byte_size, diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index 5d8bf32e2cec3..31d32745b0d61 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -49,10 +49,6 @@ inline bool TenuredGeneration::is_in(const void* p) const { return space()->is_in(p); } -inline ContiguousSpace* TenuredGeneration::first_compaction_space() const { - return space(); -} - HeapWord* TenuredGeneration::allocate(size_t word_size, bool is_tlab) { assert(!is_tlab, "TenuredGeneration does not support TLAB allocation"); diff --git a/src/hotspot/share/gc/serial/vmStructs_serial.hpp b/src/hotspot/share/gc/serial/vmStructs_serial.hpp index c99b90aa7d66e..4c2e4417a309c 100644 --- a/src/hotspot/share/gc/serial/vmStructs_serial.hpp +++ b/src/hotspot/share/gc/serial/vmStructs_serial.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, 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 @@ -53,12 +53,15 @@ nonstatic_field(SerialBlockOffsetSharedArray, _vs, VirtualSpace) \ nonstatic_field(SerialBlockOffsetSharedArray, _offset_array, u_char*) \ \ - nonstatic_field(TenuredSpace, _offsets, SerialBlockOffsetTable) + nonstatic_field(TenuredSpace, _offsets, SerialBlockOffsetTable) \ + \ + nonstatic_field(SerialHeap, _young_gen, DefNewGeneration*) \ + nonstatic_field(SerialHeap, _old_gen, TenuredGeneration*) \ #define VM_TYPES_SERIALGC(declare_type, \ declare_toplevel_type, \ declare_integer_type) \ - declare_type(SerialHeap, GenCollectedHeap) \ + declare_type(SerialHeap, CollectedHeap) \ declare_type(TenuredGeneration, Generation) \ declare_type(TenuredSpace, ContiguousSpace) \ \ diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp index 959fb3102589e..a9c11af570cd9 100644 --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp @@ -48,12 +48,6 @@ class AdaptiveSizePolicy : public CHeapObj { virtual GCPolicyKind kind() const { return _gc_adaptive_size_policy; } enum SizePolicyTrueValues { - decrease_old_gen_for_throughput_true = -7, - decrease_young_gen_for_througput_true = -6, - - 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, diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp index b7d706df6e395..c4f318561d64b 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ void CardTableBarrierSet::print_on(outputStream* st) const { // to a newly allocated object along the fast-path. We // compensate for such elided card-marks as follows: // (a) Generational, non-concurrent collectors, such as -// GenCollectedHeap(DefNew,Tenured) and +// SerialHeap(DefNew,Tenured) and // ParallelScavengeHeap(ParallelGC, ParallelOldGC) // need the card-mark if and only if the region is // in the old gen, and do not care if the card-mark diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index cccc7b168832a..0ac7faa06f057 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,8 +84,7 @@ class ParallelObjectIterator : public StackObj { // // CollectedHeap -// GenCollectedHeap -// SerialHeap +// SerialHeap // G1CollectedHeap // ParallelScavengeHeap // ShenandoahHeap diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index 80358f38e2d60..5f17c828bd7a6 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.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 @@ -30,7 +30,7 @@ #include "gc/shared/gcLocker.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/gc_globals.hpp" -#include "gc/shared/genCollectedHeap.hpp" +#include "gc/shared/softRefPolicy.hpp" #include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" #include "memory/classLoaderMetaspace.hpp" @@ -194,28 +194,6 @@ void VM_GC_HeapInspection::doit() { } } - -void VM_GenCollectForAllocation::doit() { - SvcGCMarker sgcm(SvcGCMarker::MINOR); - - GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCCauseSetter gccs(gch, _gc_cause); - _result = gch->satisfy_failed_allocation(_word_size, _tlab); - assert(_result == nullptr || gch->is_in_reserved(_result), "result not in heap"); - - if (_result == nullptr && GCLocker::is_active_and_needs_gc()) { - set_gc_locked(); - } -} - -void VM_GenCollectFull::doit() { - SvcGCMarker sgcm(SvcGCMarker::FULL); - - GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCCauseSetter gccs(gch, _gc_cause); - gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_generation); -} - VM_CollectForMetadataAllocation::VM_CollectForMetadataAllocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype, diff --git a/src/hotspot/share/gc/shared/gcVMOperations.hpp b/src/hotspot/share/gc/shared/gcVMOperations.hpp index f4bc933331267..c7a2edb135509 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.hpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.hpp @@ -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 @@ -26,7 +26,7 @@ #define SHARE_GC_SHARED_GCVMOPERATIONS_HPP #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/genCollectedHeap.hpp" +#include "gc/shared/collectorCounters.hpp" #include "memory/metaspace.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/handles.hpp" @@ -192,40 +192,6 @@ class VM_CollectForAllocation : public VM_GC_Operation { } }; -class VM_GenCollectForAllocation : public VM_CollectForAllocation { - private: - bool _tlab; // alloc is of a tlab. - public: - VM_GenCollectForAllocation(size_t word_size, - bool tlab, - uint gc_count_before) - : VM_CollectForAllocation(word_size, gc_count_before, GCCause::_allocation_failure), - _tlab(tlab) { - assert(word_size != 0, "An allocation should always be requested with this operation."); - } - ~VM_GenCollectForAllocation() {} - virtual VMOp_Type type() const { return VMOp_GenCollectForAllocation; } - virtual void doit(); -}; - -// VM operation to invoke a collection of the heap as a -// GenCollectedHeap heap. -class VM_GenCollectFull: public VM_GC_Operation { - private: - GenCollectedHeap::GenerationType _max_generation; - public: - VM_GenCollectFull(uint gc_count_before, - uint full_gc_count_before, - GCCause::Cause gc_cause, - GenCollectedHeap::GenerationType max_generation) - : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, - max_generation != GenCollectedHeap::YoungGen /* full */), - _max_generation(max_generation) { } - ~VM_GenCollectFull() {} - virtual VMOp_Type type() const { return VMOp_GenCollectFull; } - virtual void doit(); -}; - class VM_CollectForMetadataAllocation: public VM_GC_Operation { private: MetaWord* _result; diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp deleted file mode 100644 index f4c21cce6dcda..0000000000000 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "classfile/stringTable.hpp" -#include "classfile/symbolTable.hpp" -#include "classfile/vmSymbols.hpp" -#include "code/codeCache.hpp" -#include "code/icBuffer.hpp" -#include "compiler/oopMap.hpp" -#include "gc/serial/cardTableRS.hpp" -#include "gc/serial/defNewGeneration.hpp" -#include "gc/serial/genMarkSweep.hpp" -#include "gc/serial/markSweep.hpp" -#include "gc/serial/tenuredGeneration.hpp" -#include "gc/shared/cardTableBarrierSet.hpp" -#include "gc/shared/classUnloadingContext.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/collectorCounters.hpp" -#include "gc/shared/continuationGCSupport.inline.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/shared/gcInitLogger.hpp" -#include "gc/shared/gcLocker.hpp" -#include "gc/shared/gcPolicyCounters.hpp" -#include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/gcVMOperations.hpp" -#include "gc/shared/genArguments.hpp" -#include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/locationPrinter.inline.hpp" -#include "gc/shared/oopStorage.inline.hpp" -#include "gc/shared/oopStorageParState.inline.hpp" -#include "gc/shared/oopStorageSet.inline.hpp" -#include "gc/shared/scavengableNMethods.hpp" -#include "gc/shared/space.hpp" -#include "gc/shared/strongRootsScope.hpp" -#include "gc/shared/weakProcessor.hpp" -#include "gc/shared/workerThread.hpp" -#include "memory/iterator.hpp" -#include "memory/metaspaceCounters.hpp" -#include "memory/metaspaceUtils.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/handles.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/java.hpp" -#include "runtime/threads.hpp" -#include "runtime/vmThread.hpp" -#include "services/memoryService.hpp" -#include "utilities/autoRestore.hpp" -#include "utilities/debug.hpp" -#include "utilities/formatBuffer.hpp" -#include "utilities/macros.hpp" -#include "utilities/stack.inline.hpp" -#include "utilities/vmError.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmci.hpp" -#endif - -GenCollectedHeap::GenCollectedHeap(Generation::Name young, - Generation::Name old, - const char* policy_counters_name) : - CollectedHeap(), - _young_gen(nullptr), - _old_gen(nullptr), - _rem_set(nullptr), - _soft_ref_policy(), - _gc_policy_counters(new GCPolicyCounters(policy_counters_name, 2, 2)), - _incremental_collection_failed(false), - _full_collections_completed(0), - _young_manager(nullptr), - _old_manager(nullptr) { -} - -jint GenCollectedHeap::initialize() { - // Allocate space for the heap. - - ReservedHeapSpace heap_rs = allocate(HeapAlignment); - - if (!heap_rs.is_reserved()) { - vm_shutdown_during_initialization( - "Could not reserve enough space for object heap"); - return JNI_ENOMEM; - } - - initialize_reserved_region(heap_rs); - - ReservedSpace young_rs = heap_rs.first_part(MaxNewSize); - ReservedSpace old_rs = heap_rs.last_part(MaxNewSize); - - _rem_set = create_rem_set(heap_rs.region()); - _rem_set->initialize(young_rs.base(), old_rs.base()); - - CardTableBarrierSet *bs = new CardTableBarrierSet(_rem_set); - bs->initialize(); - BarrierSet::set_barrier_set(bs); - - _young_gen = new DefNewGeneration(young_rs, NewSize, MinNewSize, MaxNewSize); - _old_gen = new TenuredGeneration(old_rs, OldSize, MinOldSize, MaxOldSize, rem_set()); - - GCInitLogger::print(); - - return JNI_OK; -} - -CardTableRS* GenCollectedHeap::create_rem_set(const MemRegion& reserved_region) { - return new CardTableRS(reserved_region); -} - -ReservedHeapSpace GenCollectedHeap::allocate(size_t alignment) { - // Now figure out the total size. - const size_t pageSize = UseLargePages ? os::large_page_size() : os::vm_page_size(); - assert(alignment % pageSize == 0, "Must be"); - - // Check for overflow. - size_t total_reserved = MaxNewSize + MaxOldSize; - if (total_reserved < MaxNewSize) { - vm_exit_during_initialization("The size of the object heap + VM data exceeds " - "the maximum representable size"); - } - assert(total_reserved % alignment == 0, - "Gen size; total_reserved=" SIZE_FORMAT ", alignment=" - SIZE_FORMAT, total_reserved, alignment); - - ReservedHeapSpace heap_rs = Universe::reserve_heap(total_reserved, alignment); - size_t used_page_size = heap_rs.page_size(); - - os::trace_page_sizes("Heap", - MinHeapSize, - total_reserved, - heap_rs.base(), - heap_rs.size(), - used_page_size); - - return heap_rs; -} - -class GenIsScavengable : public BoolObjectClosure { -public: - bool do_object_b(oop obj) { - return GenCollectedHeap::heap()->is_in_young(obj); - } -}; - -static GenIsScavengable _is_scavengable; - -void GenCollectedHeap::post_initialize() { - CollectedHeap::post_initialize(); - - DefNewGeneration* def_new_gen = (DefNewGeneration*)_young_gen; - - def_new_gen->ref_processor_init(); - - MarkSweep::initialize(); - - ScavengableNMethods::initialize(&_is_scavengable); -} - -PreGenGCValues GenCollectedHeap::get_pre_gc_values() const { - const DefNewGeneration* const def_new_gen = (DefNewGeneration*) young_gen(); - - return PreGenGCValues(def_new_gen->used(), - def_new_gen->capacity(), - def_new_gen->eden()->used(), - def_new_gen->eden()->capacity(), - def_new_gen->from()->used(), - def_new_gen->from()->capacity(), - old_gen()->used(), - old_gen()->capacity()); -} - -size_t GenCollectedHeap::capacity() const { - return _young_gen->capacity() + _old_gen->capacity(); -} - -size_t GenCollectedHeap::used() const { - return _young_gen->used() + _old_gen->used(); -} - -void GenCollectedHeap::save_used_regions() { - _old_gen->save_used_region(); - _young_gen->save_used_region(); -} - -size_t GenCollectedHeap::max_capacity() const { - return _young_gen->max_capacity() + _old_gen->max_capacity(); -} - -// Update the _full_collections_completed counter -// at the end of a stop-world full GC. -unsigned int GenCollectedHeap::update_full_collections_completed() { - assert(_full_collections_completed <= _total_full_collections, - "Can't complete more collections than were started"); - _full_collections_completed = _total_full_collections; - return _full_collections_completed; -} - -// Return true if any of the following is true: -// . the allocation won't fit into the current young gen heap -// . gc locker is occupied (jni critical section) -// . heap memory is tight -- the most recent previous collection -// was a full collection because a partial collection (would -// have) failed and is likely to fail again -bool GenCollectedHeap::should_try_older_generation_allocation(size_t word_size) const { - size_t young_capacity = _young_gen->capacity_before_gc(); - return (word_size > heap_word_size(young_capacity)) - || GCLocker::is_active_and_needs_gc() - || incremental_collection_failed(); -} - -HeapWord* GenCollectedHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { - HeapWord* result = nullptr; - if (_old_gen->should_allocate(size, is_tlab)) { - result = _old_gen->expand_and_allocate(size, is_tlab); - } - if (result == nullptr) { - if (_young_gen->should_allocate(size, is_tlab)) { - result = _young_gen->expand_and_allocate(size, is_tlab); - } - } - assert(result == nullptr || is_in_reserved(result), "result not in heap"); - return result; -} - -HeapWord* GenCollectedHeap::mem_allocate_work(size_t size, - bool is_tlab) { - - HeapWord* result = nullptr; - - // Loop until the allocation is satisfied, or unsatisfied after GC. - for (uint try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { - - // First allocation attempt is lock-free. - Generation *young = _young_gen; - if (young->should_allocate(size, is_tlab)) { - result = young->par_allocate(size, is_tlab); - if (result != nullptr) { - assert(is_in_reserved(result), "result not in heap"); - return result; - } - } - uint gc_count_before; // Read inside the Heap_lock locked region. - { - MutexLocker ml(Heap_lock); - log_trace(gc, alloc)("GenCollectedHeap::mem_allocate_work: attempting locked slow path allocation"); - // Note that only large objects get a shot at being - // allocated in later generations. - bool first_only = !should_try_older_generation_allocation(size); - - result = attempt_allocation(size, is_tlab, first_only); - if (result != nullptr) { - assert(is_in_reserved(result), "result not in heap"); - return result; - } - - if (GCLocker::is_active_and_needs_gc()) { - if (is_tlab) { - return nullptr; // Caller will retry allocating individual object. - } - if (!is_maximal_no_gc()) { - // Try and expand heap to satisfy request. - result = expand_heap_and_allocate(size, is_tlab); - // Result could be null if we are out of space. - if (result != nullptr) { - return result; - } - } - - if (gclocker_stalled_count > GCLockerRetryAllocationCount) { - return nullptr; // We didn't get to do a GC and we didn't get any memory. - } - - // If this thread is not in a jni critical section, we stall - // the requestor until the critical section has cleared and - // GC allowed. When the critical section clears, a GC is - // initiated by the last thread exiting the critical section; so - // we retry the allocation sequence from the beginning of the loop, - // rather than causing more, now probably unnecessary, GC attempts. - JavaThread* jthr = JavaThread::current(); - if (!jthr->in_critical()) { - MutexUnlocker mul(Heap_lock); - // Wait for JNI critical section to be exited - GCLocker::stall_until_clear(); - gclocker_stalled_count += 1; - continue; - } else { - if (CheckJNICalls) { - fatal("Possible deadlock due to allocating while" - " in jni critical section"); - } - return nullptr; - } - } - - // Read the gc count while the heap lock is held. - gc_count_before = total_collections(); - } - - VM_GenCollectForAllocation op(size, is_tlab, gc_count_before); - VMThread::execute(&op); - if (op.prologue_succeeded()) { - result = op.result(); - if (op.gc_locked()) { - assert(result == nullptr, "must be null if gc_locked() is true"); - continue; // Retry and/or stall as necessary. - } - - assert(result == nullptr || is_in_reserved(result), - "result not in heap"); - return result; - } - - // Give a warning if we seem to be looping forever. - if ((QueuedAllocationWarningCount > 0) && - (try_count % QueuedAllocationWarningCount == 0)) { - log_warning(gc, ergo)("GenCollectedHeap::mem_allocate_work retries %d times," - " size=" SIZE_FORMAT " %s", try_count, size, is_tlab ? "(TLAB)" : ""); - } - } -} - -HeapWord* GenCollectedHeap::attempt_allocation(size_t size, - bool is_tlab, - bool first_only) { - HeapWord* res = nullptr; - - if (_young_gen->should_allocate(size, is_tlab)) { - res = _young_gen->allocate(size, is_tlab); - if (res != nullptr || first_only) { - return res; - } - } - - if (_old_gen->should_allocate(size, is_tlab)) { - res = _old_gen->allocate(size, is_tlab); - } - - return res; -} - -HeapWord* GenCollectedHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { - return mem_allocate_work(size, - false /* is_tlab */); -} - -bool GenCollectedHeap::must_clear_all_soft_refs() { - return _gc_cause == GCCause::_metadata_GC_clear_soft_refs || - _gc_cause == GCCause::_wb_full_gc; -} - -void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t size, - bool is_tlab, bool run_verification, bool clear_soft_refs) { - FormatBuffer<> title("Collect gen: %s", gen->short_name()); - GCTraceTime(Trace, gc, phases) t1(title); - TraceCollectorStats tcs(gen->counters()); - TraceMemoryManagerStats tmms(gen->gc_manager(), gc_cause(), heap()->is_young_gen(gen) ? "end of minor GC" : "end of major GC"); - - gen->stat_record()->invocations++; - gen->stat_record()->accumulated_time.start(); - - // Must be done anew before each collection because - // a previous collection will do mangling and will - // change top of some spaces. - record_gen_tops_before_GC(); - - log_trace(gc)("%s invoke=%d size=" SIZE_FORMAT, heap()->is_young_gen(gen) ? "Young" : "Old", gen->stat_record()->invocations, size * HeapWordSize); - - if (run_verification && VerifyBeforeGC) { - Universe::verify("Before GC"); - } - COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::clear()); - - // Do collection work - { - save_marks(); // save marks for all gens - - gen->collect(full, clear_soft_refs, size, is_tlab); - } - - COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::update_pointers()); - - gen->stat_record()->accumulated_time.stop(); - - update_gc_stats(gen, full); - - if (run_verification && VerifyAfterGC) { - Universe::verify("After GC"); - } -} - -void GenCollectedHeap::do_collection(bool full, - bool clear_all_soft_refs, - size_t size, - bool is_tlab, - GenerationType max_generation) { - ResourceMark rm; - DEBUG_ONLY(Thread* my_thread = Thread::current();) - - assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); - assert(my_thread->is_VM_thread(), "only VM thread"); - assert(Heap_lock->is_locked(), - "the requesting thread should have the Heap_lock"); - guarantee(!is_gc_active(), "collection is not reentrant"); - - if (GCLocker::check_active_before_gc()) { - return; // GC is disabled (e.g. JNI GetXXXCritical operation) - } - - const bool do_clear_all_soft_refs = clear_all_soft_refs || - soft_ref_policy()->should_clear_all_soft_refs(); - - ClearedAllSoftRefs casr(do_clear_all_soft_refs, soft_ref_policy()); - - AutoModifyRestore temporarily(_is_gc_active, true); - - bool complete = full && (max_generation == OldGen); - bool old_collects_young = complete && !ScavengeBeforeFullGC; - bool do_young_collection = !old_collects_young && _young_gen->should_collect(full, size, is_tlab); - - const PreGenGCValues pre_gc_values = get_pre_gc_values(); - - bool run_verification = total_collections() >= VerifyGCStartAt; - bool prepared_for_verification = false; - bool do_full_collection = false; - - if (do_young_collection) { - GCIdMark gc_id_mark; - GCTraceCPUTime tcpu(((DefNewGeneration*)_young_gen)->gc_tracer()); - GCTraceTime(Info, gc) t("Pause Young", nullptr, gc_cause(), true); - - print_heap_before_gc(); - - if (run_verification && VerifyGCLevel <= 0 && VerifyBeforeGC) { - prepare_for_verify(); - prepared_for_verification = true; - } - - gc_prologue(complete); - increment_total_collections(complete); - - collect_generation(_young_gen, - full, - size, - is_tlab, - run_verification && VerifyGCLevel <= 0, - do_clear_all_soft_refs); - - if (size > 0 && (!is_tlab || _young_gen->supports_tlab_allocation()) && - size * HeapWordSize <= _young_gen->unsafe_max_alloc_nogc()) { - // Allocation request was met by young GC. - size = 0; - } - - // Ask if young collection is enough. If so, do the final steps for young collection, - // and fallthrough to the end. - do_full_collection = should_do_full_collection(size, full, is_tlab, max_generation); - if (!do_full_collection) { - // Adjust generation sizes. - _young_gen->compute_new_size(); - - print_heap_change(pre_gc_values); - - // Track memory usage and detect low memory after GC finishes - MemoryService::track_memory_usage(); - - gc_epilogue(complete); - } - - print_heap_after_gc(); - - } else { - // No young collection, ask if we need to perform Full collection. - do_full_collection = should_do_full_collection(size, full, is_tlab, max_generation); - } - - if (do_full_collection) { - GCIdMark gc_id_mark; - GCTraceCPUTime tcpu(GenMarkSweep::gc_tracer()); - GCTraceTime(Info, gc) t("Pause Full", nullptr, gc_cause(), true); - - print_heap_before_gc(); - - if (!prepared_for_verification && run_verification && - VerifyGCLevel <= 1 && VerifyBeforeGC) { - prepare_for_verify(); - } - - if (!do_young_collection) { - gc_prologue(complete); - increment_total_collections(complete); - } - - // Accounting quirk: total full collections would be incremented when "complete" - // is set, by calling increment_total_collections above. However, we also need to - // account Full collections that had "complete" unset. - if (!complete) { - increment_total_full_collections(); - } - - 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, - full, - size, - is_tlab, - run_verification && VerifyGCLevel <= 1, - do_clear_all_soft_refs); - - CodeCache::on_gc_marking_cycle_finish(); - CodeCache::arm_all_nmethods(); - - // Adjust generation sizes. - _old_gen->compute_new_size(); - _young_gen->compute_new_size(); - - // Delete metaspaces for unloaded class loaders and clean up loader_data graph - ClassLoaderDataGraph::purge(true /* at_safepoint */); - DEBUG_ONLY(MetaspaceUtils::verify();) - - // Need to clear claim bits for the next mark. - ClassLoaderDataGraph::clear_claimed_marks(); - - // Resize the metaspace capacity after full collections - MetaspaceGC::compute_new_size(); - update_full_collections_completed(); - - print_heap_change(pre_gc_values); - - // Track memory usage and detect low memory after GC finishes - MemoryService::track_memory_usage(); - - // Need to tell the epilogue code we are done with Full GC, regardless what was - // the initial value for "complete" flag. - gc_epilogue(true); - - print_heap_after_gc(); - } -} - -bool GenCollectedHeap::should_do_full_collection(size_t size, bool full, bool is_tlab, - GenCollectedHeap::GenerationType max_gen) const { - return max_gen == OldGen && _old_gen->should_collect(full, size, is_tlab); -} - -void GenCollectedHeap::register_nmethod(nmethod* nm) { - ScavengableNMethods::register_nmethod(nm); -} - -void GenCollectedHeap::unregister_nmethod(nmethod* nm) { - ScavengableNMethods::unregister_nmethod(nm); -} - -void GenCollectedHeap::verify_nmethod(nmethod* nm) { - ScavengableNMethods::verify_nmethod(nm); -} - -void GenCollectedHeap::prune_scavengable_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) { - GCCauseSetter x(this, GCCause::_allocation_failure); - HeapWord* result = nullptr; - - assert(size != 0, "Precondition violated"); - if (GCLocker::is_active_and_needs_gc()) { - // GC locker is active; instead of a collection we will attempt - // to expand the heap, if there's room for expansion. - if (!is_maximal_no_gc()) { - result = expand_heap_and_allocate(size, is_tlab); - } - return result; // Could be null if we are out of space. - } else if (!incremental_collection_will_fail(false /* don't consult_young */)) { - // Do an incremental collection. - do_collection(false, // full - false, // clear_all_soft_refs - size, // size - is_tlab, // is_tlab - GenCollectedHeap::OldGen); // max_generation - } else { - log_trace(gc)(" :: Trying full because partial may fail :: "); - // Try a full collection; see delta for bug id 6266275 - // for the original code and why this has been simplified - // with from-space allocation criteria modified and - // such allocation moved out of the safepoint path. - do_collection(true, // full - false, // clear_all_soft_refs - size, // size - is_tlab, // is_tlab - GenCollectedHeap::OldGen); // max_generation - } - - result = attempt_allocation(size, is_tlab, false /*first_only*/); - - if (result != nullptr) { - assert(is_in_reserved(result), "result not in heap"); - return result; - } - - // OK, collection failed, try expansion. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; - } - - // If we reach this point, we're really out of memory. Try every trick - // we can to reclaim memory. Force collection of soft references. Force - // a complete compaction of the heap. Any additional methods for finding - // free memory should be here, especially if they are expensive. If this - // attempt fails, an OOM exception will be thrown. - { - UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted - - do_collection(true, // full - true, // clear_all_soft_refs - size, // size - is_tlab, // is_tlab - GenCollectedHeap::OldGen); // max_generation - } - - result = attempt_allocation(size, is_tlab, false /* first_only */); - if (result != nullptr) { - assert(is_in_reserved(result), "result not in heap"); - return result; - } - - assert(!soft_ref_policy()->should_clear_all_soft_refs(), - "Flag should have been handled and cleared prior to this point"); - - // What else? We might try synchronous finalization later. If the total - // space available is large enough for the allocation, then a more - // complete compaction phase than we've tried so far might be - // appropriate. - return nullptr; -} - -#ifdef ASSERT -class AssertNonScavengableClosure: public OopClosure { -public: - virtual void do_oop(oop* p) { - assert(!GenCollectedHeap::heap()->is_in_partial_collection(*p), - "Referent should not be scavengable."); } - virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } -}; -static AssertNonScavengableClosure assert_is_non_scavengable_closure; -#endif - -void GenCollectedHeap::process_roots(ScanningOption so, - OopClosure* strong_roots, - CLDClosure* strong_cld_closure, - CLDClosure* weak_cld_closure, - CodeBlobToOopClosure* code_roots) { - // General roots. - assert(code_roots != nullptr, "code root closure should always be set"); - - ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure); - - // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway - CodeBlobToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? nullptr : code_roots; - - Threads::oops_do(strong_roots, roots_from_code_p); - - OopStorageSet::strong_oops_do(strong_roots); - - if (so & SO_ScavengeCodeCache) { - assert(code_roots != nullptr, "must supply closure for code cache"); - - // We only visit parts of the CodeCache when scavenging. - ScavengableNMethods::nmethods_do(code_roots); - } - if (so & SO_AllCodeCache) { - assert(code_roots != nullptr, "must supply closure for code cache"); - - // CMSCollector uses this to do intermediate-strength collections. - // We scan the entire code cache, since CodeCache::do_unloading is not called. - CodeCache::blobs_do(code_roots); - } - // Verify that the code cache contents are not subject to - // movement by a scavenging collection. - DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations)); - DEBUG_ONLY(ScavengableNMethods::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); -} - -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(); -} - -// public collection interfaces -void GenCollectedHeap::collect(GCCause::Cause cause) { - // The caller doesn't have the Heap_lock - assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); - - unsigned int gc_count_before; - unsigned int full_gc_count_before; - - { - MutexLocker ml(Heap_lock); - // Read the GC count while holding the Heap_lock - gc_count_before = total_collections(); - full_gc_count_before = total_full_collections(); - } - - if (GCLocker::should_discard(cause, gc_count_before)) { - return; - } - - bool should_run_young_gc = (cause == GCCause::_wb_young_gc) - || (cause == GCCause::_gc_locker) - DEBUG_ONLY(|| (cause == GCCause::_scavenge_alot)); - - const GenerationType max_generation = should_run_young_gc - ? YoungGen - : OldGen; - - while (true) { - VM_GenCollectFull op(gc_count_before, full_gc_count_before, - cause, max_generation); - VMThread::execute(&op); - - if (!GCCause::is_explicit_full_gc(cause)) { - return; - } - - { - MutexLocker ml(Heap_lock); - // Read the GC count while holding the Heap_lock - if (full_gc_count_before != total_full_collections()) { - return; - } - } - - if (GCLocker::is_active_and_needs_gc()) { - // If GCLocker is active, wait until clear before retrying. - GCLocker::stall_until_clear(); - } - } -} - -void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) { - do_full_collection(clear_all_soft_refs, OldGen); -} - -void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, - GenerationType last_generation) { - do_collection(true, // full - clear_all_soft_refs, // clear_all_soft_refs - 0, // size - false, // is_tlab - last_generation); // last_generation - // Hack XXX FIX ME !!! - // A scavenge may not have been attempted, or may have - // been attempted and failed, because the old gen was too full - if (gc_cause() == GCCause::_gc_locker && incremental_collection_failed()) { - log_debug(gc, jni)("GC locker: Trying a full collection because scavenge failed"); - // This time allow the old gen to be collected as well - do_collection(true, // full - clear_all_soft_refs, // clear_all_soft_refs - 0, // size - false, // is_tlab - OldGen); // last_generation - } -} - -bool GenCollectedHeap::is_in_young(const void* p) const { - bool result = p < _old_gen->reserved().start(); - assert(result == _young_gen->is_in_reserved(p), - "incorrect test - result=%d, p=" PTR_FORMAT, result, p2i(p)); - return result; -} - -bool GenCollectedHeap::requires_barriers(stackChunkOop obj) const { - return !is_in_young(obj); -} - -// Returns "TRUE" iff "p" points into the committed areas of the heap. -bool GenCollectedHeap::is_in(const void* p) const { - return _young_gen->is_in(p) || _old_gen->is_in(p); -} - -#ifdef ASSERT -// Don't implement this by using is_in_young(). This method is used -// in some cases to check that is_in_young() is correct. -bool GenCollectedHeap::is_in_partial_collection(const void* p) { - assert(is_in_reserved(p) || p == nullptr, - "Does not work if address is non-null and outside of the heap"); - return p < _young_gen->reserved().end() && p != nullptr; -} -#endif - -void GenCollectedHeap::object_iterate(ObjectClosure* cl) { - _young_gen->object_iterate(cl); - _old_gen->object_iterate(cl); -} - -HeapWord* GenCollectedHeap::block_start(const void* addr) const { - assert(is_in_reserved(addr), "block_start of address outside of heap"); - if (_young_gen->is_in_reserved(addr)) { - assert(_young_gen->is_in(addr), "addr should be in allocated part of generation"); - return _young_gen->block_start(addr); - } - - assert(_old_gen->is_in_reserved(addr), "Some generation should contain the address"); - assert(_old_gen->is_in(addr), "addr should be in allocated part of generation"); - return _old_gen->block_start(addr); -} - -bool GenCollectedHeap::block_is_obj(const HeapWord* addr) const { - assert(is_in_reserved(addr), "block_is_obj of address outside of heap"); - assert(block_start(addr) == addr, "addr must be a block start"); - if (_young_gen->is_in_reserved(addr)) { - return _young_gen->block_is_obj(addr); - } - - assert(_old_gen->is_in_reserved(addr), "Some generation should contain the address"); - return _old_gen->block_is_obj(addr); -} - -size_t GenCollectedHeap::tlab_capacity(Thread* thr) const { - assert(!_old_gen->supports_tlab_allocation(), "Old gen supports TLAB allocation?!"); - assert(_young_gen->supports_tlab_allocation(), "Young gen doesn't support TLAB allocation?!"); - return _young_gen->tlab_capacity(); -} - -size_t GenCollectedHeap::tlab_used(Thread* thr) const { - assert(!_old_gen->supports_tlab_allocation(), "Old gen supports TLAB allocation?!"); - assert(_young_gen->supports_tlab_allocation(), "Young gen doesn't support TLAB allocation?!"); - return _young_gen->tlab_used(); -} - -size_t GenCollectedHeap::unsafe_max_tlab_alloc(Thread* thr) const { - assert(!_old_gen->supports_tlab_allocation(), "Old gen supports TLAB allocation?!"); - assert(_young_gen->supports_tlab_allocation(), "Young gen doesn't support TLAB allocation?!"); - return _young_gen->unsafe_max_tlab_alloc(); -} - -HeapWord* GenCollectedHeap::allocate_new_tlab(size_t min_size, - size_t requested_size, - size_t* actual_size) { - HeapWord* result = mem_allocate_work(requested_size /* size */, - true /* is_tlab */); - if (result != nullptr) { - *actual_size = requested_size; - } - - return result; -} - -void GenCollectedHeap::prepare_for_verify() { - ensure_parsability(false); // no need to retire TLABs -} - -void GenCollectedHeap::generation_iterate(GenClosure* cl, - bool old_to_young) { - if (old_to_young) { - cl->do_generation(_old_gen); - cl->do_generation(_young_gen); - } else { - cl->do_generation(_young_gen); - cl->do_generation(_old_gen); - } -} - -bool GenCollectedHeap::is_maximal_no_gc() const { - return _young_gen->is_maximal_no_gc() && _old_gen->is_maximal_no_gc(); -} - -void GenCollectedHeap::save_marks() { - _young_gen->save_marks(); - _old_gen->save_marks(); -} - -GenCollectedHeap* GenCollectedHeap::heap() { - // SerialHeap is the only subtype of GenCollectedHeap. - 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(); - - log_debug(gc, verify)("%s", _young_gen->name()); - _young_gen->verify(); - - log_debug(gc, verify)("RemSet"); - rem_set()->verify(); -} - -void GenCollectedHeap::print_on(outputStream* st) const { - if (_young_gen != nullptr) { - _young_gen->print_on(st); - } - if (_old_gen != nullptr) { - _old_gen->print_on(st); - } - MetaspaceUtils::print_on(st); -} - -void GenCollectedHeap::gc_threads_do(ThreadClosure* tc) const { -} - -bool GenCollectedHeap::print_location(outputStream* st, void* addr) const { - return BlockLocationPrinter::print_location(st, addr); -} - -void GenCollectedHeap::print_tracing_info() const { - if (log_is_enabled(Debug, gc, heap, exit)) { - LogStreamHandle(Debug, gc, heap, exit) lsh; - _young_gen->print_summary_info_on(&lsh); - _old_gen->print_summary_info_on(&lsh); - } -} - -void GenCollectedHeap::print_heap_change(const PreGenGCValues& pre_gc_values) const { - const DefNewGeneration* const def_new_gen = (DefNewGeneration*) young_gen(); - - log_info(gc, heap)(HEAP_CHANGE_FORMAT" " - HEAP_CHANGE_FORMAT" " - HEAP_CHANGE_FORMAT, - HEAP_CHANGE_FORMAT_ARGS(def_new_gen->short_name(), - pre_gc_values.young_gen_used(), - pre_gc_values.young_gen_capacity(), - def_new_gen->used(), - def_new_gen->capacity()), - HEAP_CHANGE_FORMAT_ARGS("Eden", - pre_gc_values.eden_used(), - pre_gc_values.eden_capacity(), - def_new_gen->eden()->used(), - def_new_gen->eden()->capacity()), - HEAP_CHANGE_FORMAT_ARGS("From", - pre_gc_values.from_used(), - pre_gc_values.from_capacity(), - def_new_gen->from()->used(), - def_new_gen->from()->capacity())); - log_info(gc, heap)(HEAP_CHANGE_FORMAT, - HEAP_CHANGE_FORMAT_ARGS(old_gen()->short_name(), - pre_gc_values.old_gen_used(), - pre_gc_values.old_gen_capacity(), - old_gen()->used(), - old_gen()->capacity())); - MetaspaceUtils::print_metaspace_change(pre_gc_values.metaspace_sizes()); -} - -class GenGCPrologueClosure: public GenCollectedHeap::GenClosure { - private: - bool _full; - public: - void do_generation(Generation* gen) { - gen->gc_prologue(_full); - } - GenGCPrologueClosure(bool full) : _full(full) {}; -}; - -void GenCollectedHeap::gc_prologue(bool full) { - assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); - - // Fill TLAB's and such - ensure_parsability(true); // retire TLABs - - // Walk generations - GenGCPrologueClosure blk(full); - generation_iterate(&blk, false); // not old-to-young. -}; - -class GenGCEpilogueClosure: public GenCollectedHeap::GenClosure { - private: - bool _full; - public: - void do_generation(Generation* gen) { - gen->gc_epilogue(_full); - } - GenGCEpilogueClosure(bool full) : _full(full) {}; -}; - -void GenCollectedHeap::gc_epilogue(bool full) { -#if COMPILER2_OR_JVMCI - assert(DerivedPointerTable::is_empty(), "derived pointer present"); -#endif // COMPILER2_OR_JVMCI - - resize_all_tlabs(); - - GenGCEpilogueClosure blk(full); - generation_iterate(&blk, false); // not old-to-young. - - MetaspaceCounters::update_performance_counters(); -}; - -#ifndef PRODUCT -class GenGCSaveTopsBeforeGCClosure: public GenCollectedHeap::GenClosure { - private: - public: - void do_generation(Generation* gen) { - gen->record_spaces_top(); - } -}; - -void GenCollectedHeap::record_gen_tops_before_GC() { - if (ZapUnusedHeapArea) { - GenGCSaveTopsBeforeGCClosure blk; - generation_iterate(&blk, false); // not old-to-young. - } -} -#endif // not PRODUCT diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp deleted file mode 100644 index 72548f6e2f54a..0000000000000 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_GENCOLLECTEDHEAP_HPP -#define SHARE_GC_SHARED_GENCOLLECTEDHEAP_HPP - -#include "gc/serial/generation.hpp" -#include "gc/shared/collectedHeap.hpp" -#include "gc/shared/oopStorageParState.hpp" -#include "gc/shared/preGCValues.hpp" -#include "gc/shared/softRefPolicy.hpp" - -class CardTableRS; -class GCPolicyCounters; - -// A "GenCollectedHeap" is a CollectedHeap that uses generational -// collection. It has two generations, young and old. -class GenCollectedHeap : public CollectedHeap { - friend class Generation; - friend class DefNewGeneration; - friend class TenuredGeneration; - friend class GenMarkSweep; - friend class VM_GenCollectForAllocation; - friend class VM_GenCollectFull; - friend class VM_GC_HeapInspection; - friend class VM_HeapDumper; - friend class HeapInspection; - friend class GCCauseSetter; - friend class VMStructs; -public: - friend class VM_PopulateDumpSharedSpace; - - enum GenerationType { - YoungGen, - OldGen - }; - -protected: - Generation* _young_gen; - Generation* _old_gen; - -private: - // The singleton CardTable Remembered Set. - CardTableRS* _rem_set; - - SoftRefPolicy _soft_ref_policy; - - GCPolicyCounters* _gc_policy_counters; - - // Indicates that the most recent previous incremental collection failed. - // The flag is cleared when an action is taken that might clear the - // condition that caused that incremental collection to fail. - bool _incremental_collection_failed; - - // In support of ExplicitGCInvokesConcurrent functionality - unsigned int _full_collections_completed; - - // Collects the given generation. - void collect_generation(Generation* gen, bool full, size_t size, bool is_tlab, - bool run_verification, bool clear_soft_refs); - - // Reserve aligned space for the heap as needed by the contained generations. - ReservedHeapSpace allocate(size_t alignment); - - PreGenGCValues get_pre_gc_values() const; - -protected: - - GCMemoryManager* _young_manager; - GCMemoryManager* _old_manager; - - // Helper functions for allocation - HeapWord* attempt_allocation(size_t size, - bool is_tlab, - bool first_only); - - // Helper function for two callbacks below. - // Considers collection of the first max_level+1 generations. - void do_collection(bool full, - bool clear_all_soft_refs, - size_t size, - bool is_tlab, - GenerationType max_generation); - - // Callback from VM_GenCollectForAllocation operation. - // This function does everything necessary/possible to satisfy an - // allocation request that failed in the youngest generation that should - // have handled it (including collection, expansion, etc.) - HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab); - - // Callback from VM_GenCollectFull operation. - // Perform a full collection of the first max_level+1 generations. - void do_full_collection(bool clear_all_soft_refs) override; - void do_full_collection(bool clear_all_soft_refs, GenerationType max_generation); - - // Does the "cause" of GC indicate that - // we absolutely __must__ clear soft refs? - bool must_clear_all_soft_refs(); - - GenCollectedHeap(Generation::Name young, - Generation::Name old, - const char* policy_counters_name); - -public: - - // Returns JNI_OK on success - jint initialize() override; - virtual CardTableRS* create_rem_set(const MemRegion& reserved_region); - - // Does operations required after initialization has been done. - void post_initialize() override; - - Generation* young_gen() const { return _young_gen; } - Generation* old_gen() const { return _old_gen; } - - bool is_young_gen(const Generation* gen) const { return gen == _young_gen; } - bool is_old_gen(const Generation* gen) const { return gen == _old_gen; } - - MemRegion reserved_region() const { return _reserved; } - bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } - - SoftRefPolicy* soft_ref_policy() override { return &_soft_ref_policy; } - - // Performance Counter support - GCPolicyCounters* counters() { return _gc_policy_counters; } - - size_t capacity() const override; - size_t used() const override; - - // Save the "used_region" for both generations. - void save_used_regions(); - - size_t max_capacity() const override; - - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; - - // Perform a full collection of the heap; intended for use in implementing - // "System.gc". This implies as full a collection as the CollectedHeap - // supports. Caller does not hold the Heap_lock on entry. - void collect(GCCause::Cause cause) override; - - // Returns "TRUE" iff "p" points into the committed areas of the heap. - // The methods is_in() and is_in_youngest() may be expensive to compute - // in general, so, to prevent their inadvertent use in product jvm's, we - // restrict their use to assertion checking or verification only. - bool is_in(const void* p) const override; - - // Returns true if p points into the reserved space for the young generation. - // Assumes the young gen address range is less than that of the old gen. - bool is_in_young(const void* p) const; - - bool requires_barriers(stackChunkOop obj) const override; - -#ifdef ASSERT - bool is_in_partial_collection(const void* p); -#endif - - // Optimized nmethod scanning support routines - void register_nmethod(nmethod* nm) override; - void unregister_nmethod(nmethod* nm) override; - void verify_nmethod(nmethod* nm) override; - - void prune_scavengable_nmethods(); - void prune_unlinked_nmethods(); - - // Iteration functions. - void object_iterate(ObjectClosure* cl) override; - - // A CollectedHeap is divided into a dense sequence of "blocks"; that is, - // each address in the (reserved) heap is a member of exactly - // one block. The defining characteristic of a block is that it is - // possible to find its size, and thus to progress forward to the next - // block. (Blocks may be of different sizes.) Thus, blocks may - // represent Java objects, or they might be free blocks in a - // free-list-based heap (or subheap), as long as the two kinds are - // distinguishable and the size of each is determinable. - - // Returns the address of the start of the "block" that contains the - // address "addr". We say "blocks" instead of "object" since some heaps - // may not pack objects densely; a chunk may either be an object or a - // non-object. - HeapWord* block_start(const void* addr) const; - - // Requires "addr" to be the start of a block, and returns "TRUE" iff - // the block is an object. Assumes (and verifies in non-product - // builds) that addr is in the allocated part of the heap and is - // the start of a chunk. - bool block_is_obj(const HeapWord* addr) const; - - // Section on TLAB's. - size_t tlab_capacity(Thread* thr) const override; - size_t tlab_used(Thread* thr) const override; - size_t unsafe_max_tlab_alloc(Thread* thr) const override; - HeapWord* allocate_new_tlab(size_t min_size, - size_t requested_size, - size_t* actual_size) override; - - // Total number of full collections completed. - unsigned int total_full_collections_completed() { - assert(_full_collections_completed <= _total_full_collections, - "Can't complete more collections than were started"); - return _full_collections_completed; - } - - // Update above counter, as appropriate, at the end of a stop-world GC cycle - unsigned int update_full_collections_completed(); - - // Update the gc statistics for each generation. - void update_gc_stats(Generation* current_generation, bool full) { - _old_gen->update_gc_stats(current_generation, full); - } - - bool no_gc_in_progress() { return !is_gc_active(); } - - void prepare_for_verify() override; - void verify(VerifyOption option) override; - - void print_on(outputStream* st) const override; - void gc_threads_do(ThreadClosure* tc) const override; - void print_tracing_info() const override; - - // Used to print information about locations in the hs_err file. - bool print_location(outputStream* st, void* addr) const override; - - void print_heap_change(const PreGenGCValues& pre_gc_values) const; - - // The functions below are helper functions that a subclass of - // "CollectedHeap" can use in the implementation of its virtual - // functions. - - class GenClosure : public StackObj { - public: - virtual void do_generation(Generation* gen) = 0; - }; - - // Apply "cl.do_generation" to all generations in the heap - // If "old_to_young" determines the order. - void generation_iterate(GenClosure* cl, bool old_to_young); - - // Return "true" if all generations have reached the - // maximal committed limit that they can reach, without a garbage - // collection. - virtual bool is_maximal_no_gc() const override; - - // This function returns the CardTableRS object that allows us to scan - // generations in a fully generational heap. - CardTableRS* rem_set() { return _rem_set; } - - // Convenience function to be used in situations where the heap type can be - // asserted to be this type. - static GenCollectedHeap* heap(); - - // The ScanningOption determines which of the roots - // the closure is applied to: - // "SO_None" does none; - enum ScanningOption { - SO_None = 0x0, - SO_AllCodeCache = 0x8, - SO_ScavengeCodeCache = 0x10 - }; - - protected: - virtual void gc_prologue(bool full); - virtual void gc_epilogue(bool full); - - public: - // Apply closures on various roots in Young GC or marking/adjust phases of Full GC. - void process_roots(ScanningOption so, - OopClosure* strong_roots, - CLDClosure* strong_cld_closure, - 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. - void save_marks(); - - // Returns "true" iff no allocations have occurred since the last - // call to "save_marks". - bool no_allocs_since_save_marks(); - - // Returns true if an incremental collection is likely to fail. - // We optionally consult the young gen, if asked to do so; - // otherwise we base our answer on whether the previous incremental - // collection attempt failed with no corrective action as of yet. - bool incremental_collection_will_fail(bool consult_young) { - // The first disjunct remembers if an incremental collection failed, even - // when we thought (second disjunct) that it would not. - return incremental_collection_failed() || - (consult_young && !_young_gen->collection_attempt_is_safe()); - } - - // If a generation bails out of an incremental collection, - // it sets this flag. - bool incremental_collection_failed() const { - return _incremental_collection_failed; - } - void set_incremental_collection_failed() { - _incremental_collection_failed = true; - } - void clear_incremental_collection_failed() { - _incremental_collection_failed = false; - } - -private: - // Return true if an allocation should be attempted in the older generation - // if it fails in the younger generation. Return false, otherwise. - bool should_try_older_generation_allocation(size_t word_size) const; - - // Try to allocate space by expanding the heap. - HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); - - 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; - - // Return true if we need to perform full collection. - bool should_do_full_collection(size_t size, bool full, - bool is_tlab, GenerationType max_gen) const; -}; - -#endif // SHARE_GC_SHARED_GENCOLLECTEDHEAP_HPP diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 8ac9a3fc783d7..6c6f83177d204 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/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 1c2afaa8b70ea..1a9e726625a2e 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.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 @@ -26,7 +26,6 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/space.hpp" #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.inline.hpp" @@ -35,19 +34,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 +52,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 +62,6 @@ void ContiguousSpace::initialize(MemRegion mr, if (clear_space) { clear(mangle_space); } - set_compaction_top(bottom); _next_compaction_space = nullptr; } @@ -80,11 +71,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 +101,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 +243,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 5d559f74f5eef..85f870ba1e2af 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 9c4c2864cedb6..bfaf84e8fac01 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/spaceDecorator.hpp b/src/hotspot/share/gc/shared/spaceDecorator.hpp index 14ee14352d151..688be70bada39 100644 --- a/src/hotspot/share/gc/shared/spaceDecorator.hpp +++ b/src/hotspot/share/gc/shared/spaceDecorator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ class SpaceDecorator: public AllStatic { // area and provides the methods for doing the piece meal mangling. // Methods for doing spaces and full checking of the mangling are // included. The full checking is done if DEBUG_MANGLING is defined. -// GenSpaceMangler is used with the GenCollectedHeap collectors and +// GenSpaceMangler is used with the SerialHeap collectors and // MutableSpaceMangler is used with the ParallelScavengeHeap collectors. // These subclasses abstract the differences in the types of spaces used // by each heap. @@ -122,7 +122,7 @@ class SpaceMangler: public CHeapObj { class ContiguousSpace; class MutableSpace; -// For use with GenCollectedHeap's +// For use with SerialHeap's class GenSpaceMangler: public SpaceMangler { ContiguousSpace* _sp; diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index 696cdc00dc520..472a02c012a38 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "gc/shared/ageTable.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/space.hpp" #if INCLUDE_EPSILONGC @@ -99,10 +98,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*) \ \ @@ -113,9 +108,6 @@ nonstatic_field(Generation::StatRecord, invocations, int) \ nonstatic_field(Generation::StatRecord, accumulated_time, elapsedTimer) \ \ - nonstatic_field(GenCollectedHeap, _young_gen, Generation*) \ - nonstatic_field(GenCollectedHeap, _old_gen, Generation*) \ - \ nonstatic_field(MemRegion, _start, HeapWord*) \ nonstatic_field(MemRegion, _word_size, size_t) \ \ @@ -150,7 +142,6 @@ /******************************************/ \ \ declare_toplevel_type(CollectedHeap) \ - declare_type(GenCollectedHeap, CollectedHeap) \ declare_toplevel_type(Generation) \ declare_toplevel_type(Space) \ declare_type(ContiguousSpace, Space) \ @@ -179,9 +170,6 @@ declare_toplevel_type(CardTableBarrierSet**) \ declare_toplevel_type(CollectedHeap*) \ declare_toplevel_type(ContiguousSpace*) \ - declare_toplevel_type(DefNewGeneration*) \ - declare_toplevel_type(GenCollectedHeap*) \ - declare_toplevel_type(Generation*) \ declare_toplevel_type(HeapWord*) \ declare_toplevel_type(HeapWord* volatile) \ declare_toplevel_type(MemRegion*) \ diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index b64c5050a2230..49e43c284fad9 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -31,6 +31,7 @@ #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" +#include "runtime/safepoint.hpp" WorkerTaskDispatcher::WorkerTaskDispatcher() : _task(nullptr), @@ -141,40 +142,44 @@ void WorkerThreads::threads_do(ThreadClosure* tc) const { } } -void WorkerThreads::set_indirectly_suspendible_threads() { +template +void WorkerThreads::threads_do_f(Function function) const { + for (uint i = 0; i < _created_workers; i++) { + function(_workers[i]); + } +} + +void WorkerThreads::set_indirect_states() { #ifdef ASSERT - class SetIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { + const bool is_suspendible = Thread::current()->is_suspendible_thread(); + const bool is_safepointed = Thread::current()->is_VM_thread() && SafepointSynchronize::is_at_safepoint(); + + threads_do_f([&](Thread* thread) { + assert(!thread->is_indirectly_suspendible_thread(), "Unexpected"); + assert(!thread->is_indirectly_safepoint_thread(), "Unexpected"); + if (is_suspendible) { thread->set_indirectly_suspendible_thread(); } - }; - - if (Thread::current()->is_suspendible_thread()) { - SetIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + if (is_safepointed) { + thread->set_indirectly_safepoint_thread(); + } + }); #endif } -void WorkerThreads::clear_indirectly_suspendible_threads() { +void WorkerThreads::clear_indirect_states() { #ifdef ASSERT - class ClearIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { - thread->clear_indirectly_suspendible_thread(); - } - }; - - if (Thread::current()->is_suspendible_thread()) { - ClearIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + threads_do_f([&](Thread* thread) { + thread->clear_indirectly_suspendible_thread(); + thread->clear_indirectly_safepoint_thread(); + }); #endif } void WorkerThreads::run_task(WorkerTask* task) { - set_indirectly_suspendible_threads(); + set_indirect_states(); _dispatcher.coordinator_distribute_task(task, _active_workers); - clear_indirectly_suspendible_threads(); + clear_indirect_states(); } void WorkerThreads::run_task(WorkerTask* task, uint num_workers) { diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index 39687e2581c25..642c8d93f5926 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -93,8 +93,8 @@ class WorkerThreads : public CHeapObj { WorkerThread* create_worker(uint name_suffix); - void set_indirectly_suspendible_threads(); - void clear_indirectly_suspendible_threads(); + void set_indirect_states(); + void clear_indirect_states(); protected: virtual void on_create_worker(WorkerThread* worker) {} @@ -111,6 +111,8 @@ class WorkerThreads : public CHeapObj { uint set_active_workers(uint num_workers); void threads_do(ThreadClosure* tc) const; + template + void threads_do_f(Function function) const; const char* name() const { return _name; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 049d8286ed448..f34b1cae8fb04 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -1104,7 +1104,7 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_resh return nullptr; } - return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN()); + return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN(), false); } return nullptr; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index c7284fbceadbd..cde8307659f36 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -112,11 +112,15 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { ShenandoahBreakpointMarkScope breakpoint_mark_scope(cause); // Concurrent mark roots entry_mark_roots(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_outside_cycle)) return false; + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_outside_cycle)) { + return false; + } // Continue concurrent mark entry_mark(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) return false; + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { + return false; + } } // Complete marking under STW, and start evacuation @@ -161,16 +165,22 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { if (heap->is_evacuation_in_progress()) { // Concurrently evacuate entry_evacuate(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_evac)) return false; + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_evac)) { + return false; + } // Perform update-refs phase. vmop_entry_init_updaterefs(); entry_updaterefs(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_updaterefs)) return false; + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_updaterefs)) { + return false; + } // Concurrent update thread roots entry_update_thread_roots(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_updaterefs)) return false; + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_updaterefs)) { + return false; + } vmop_entry_final_updaterefs(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index d8398bb1ed8b3..e7cf402a52785 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 18fd09ead0ade..4cef5378d30bc 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/shenandoahInitLogger.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp index 9f0233dd08c14..db5a68d584e90 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Red Hat, Inc. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,37 +30,26 @@ #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" #include "logging/log.hpp" -#include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" +void ShenandoahInitLogger::print() { + ShenandoahInitLogger init_log; + init_log.print_all(); +} + void ShenandoahInitLogger::print_heap() { GCInitLogger::print_heap(); - ShenandoahHeap* heap = ShenandoahHeap::heap(); - - log_info(gc, init)("Mode: %s", - heap->mode()->name()); - - log_info(gc, init)("Heuristics: %s", - heap->heuristics()->name()); - - log_info(gc, init)("Heap Region Count: " SIZE_FORMAT, - ShenandoahHeapRegion::region_count()); - - log_info(gc, init)("Heap Region Size: " SIZE_FORMAT "%s", - byte_size_in_exact_unit(ShenandoahHeapRegion::region_size_bytes()), - exact_unit_for_byte_size(ShenandoahHeapRegion::region_size_bytes())); - - log_info(gc, init)("TLAB Size Max: " SIZE_FORMAT "%s", - byte_size_in_exact_unit(ShenandoahHeapRegion::max_tlab_size_bytes()), - exact_unit_for_byte_size(ShenandoahHeapRegion::max_tlab_size_bytes())); - - log_info(gc, init)("Humongous Object Threshold: " SIZE_FORMAT "%s", - byte_size_in_exact_unit(ShenandoahHeapRegion::humongous_threshold_bytes()), - exact_unit_for_byte_size(ShenandoahHeapRegion::humongous_threshold_bytes())); + log_info(gc, init)("Heap Region Count: " SIZE_FORMAT, ShenandoahHeapRegion::region_count()); + log_info(gc, init)("Heap Region Size: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::region_size_bytes())); + log_info(gc, init)("TLAB Size Max: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::max_tlab_size_bytes())); + log_info(gc, init)("Humongous Object Threshold: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::humongous_threshold_bytes())); } -void ShenandoahInitLogger::print() { - ShenandoahInitLogger init_log; - init_log.print_all(); +void ShenandoahInitLogger::print_gc_specific() { + GCInitLogger::print_gc_specific(); + + ShenandoahHeap* heap = ShenandoahHeap::heap(); + log_info(gc, init)("Mode: %s", heap->mode()->name()); + log_info(gc, init)("Heuristics: %s", heap->heuristics()->name()); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.hpp b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.hpp index 98c918c58f741..8c0da41339978 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.hpp @@ -29,7 +29,8 @@ class ShenandoahInitLogger : public GCInitLogger { protected: - virtual void print_heap(); + void print_heap() override; + void print_gc_specific() override; public: static void print(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp index faf5172bec0a5..8dbd9c4d26f7d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp @@ -27,6 +27,7 @@ #include "gc/shenandoah/shenandoahNumberSeq.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" +#include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "memory/allocation.hpp" class ShenandoahHeap; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 8a84b4eaa66d3..90b51160e7a9b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -34,6 +34,8 @@ #include "runtime/mutex.hpp" #include "utilities/debug.hpp" +class ShenandoahHeap; + template class BufferedOverflowTaskQueue: public OverflowTaskQueue { diff --git a/src/hotspot/share/gc/z/zBarrier.inline.hpp b/src/hotspot/share/gc/z/zBarrier.inline.hpp index e0d83619934da..2c81c14865b51 100644 --- a/src/hotspot/share/gc/z/zBarrier.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp @@ -26,14 +26,13 @@ #include "gc/z/zBarrier.hpp" -#include "code/codeCache.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zResurrection.inline.hpp" +#include "gc/z/zVerify.hpp" #include "oops/oop.hpp" #include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" // A self heal must always "upgrade" the address metadata bits in // accordance with the metadata bits state machine. The following @@ -320,17 +319,9 @@ inline zaddress ZBarrier::make_load_good_no_relocate(zpointer o) { return remap(ZPointer::uncolor_unsafe(o), remap_generation(o)); } -inline void z_assert_is_barrier_safe() { - assert(!Thread::current()->is_ConcurrentGC_thread() || /* Need extra checks for ConcurrentGCThreads */ - Thread::current()->is_suspendible_thread() || /* Thread prevents safepoints */ - Thread::current()->is_indirectly_suspendible_thread() || /* Coordinator thread prevents safepoints */ - SafepointSynchronize::is_at_safepoint(), /* Is at safepoint */ - "Shouldn't perform load barrier"); -} - template inline zaddress ZBarrier::barrier(ZBarrierFastPath fast_path, ZBarrierSlowPath slow_path, ZBarrierColor color, volatile zpointer* p, zpointer o, bool allow_null) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); // Fast path if (fast_path(o)) { diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 151ccb517d744..d53cdad3c5e06 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -21,7 +21,6 @@ * questions. */ -#include "gc/z/zAddress.hpp" #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" #include "gc/shared/gcHeapSummary.hpp" diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 5e42fbd7ef8d9..0396a3f7516a0 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -286,6 +286,10 @@ void ZGeneration::desynchronize_relocation() { _relocate.desynchronize(); } +bool ZGeneration::is_relocate_queue_active() const { + return _relocate.is_queue_active(); +} + void ZGeneration::reset_statistics() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); _freed = 0; @@ -1497,7 +1501,7 @@ void ZGenerationOld::remap_young_roots() { uint remap_nworkers = clamp(ZGeneration::young()->workers()->active_workers() + prev_nworkers, 1u, ZOldGCThreads); _workers.set_active_workers(remap_nworkers); - // TODO: The STS joiner is only needed to satisfy z_assert_is_barrier_safe that doesn't + // TODO: The STS joiner is only needed to satisfy ZBarrier::assert_is_state_barrier_safe that doesn't // understand the driver locker. Consider making the assert aware of the driver locker. SuspendibleThreadSetJoiner sts_joiner; diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 23736f45b7be7..32762a50b6278 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -166,6 +166,7 @@ class ZGeneration { // Relocation void synchronize_relocation(); void desynchronize_relocation(); + bool is_relocate_queue_active() const; zaddress relocate_or_remap_object(zaddress_unsafe addr); zaddress remap_object(zaddress_unsafe addr); diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp index bcd9dd844052b..c764227061e88 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; @@ -101,9 +101,9 @@ uint ZHeuristics::nconcurrent_workers() { } size_t ZHeuristics::significant_heap_overhead() { - return MaxHeapSize * ZFragmentationLimit; + return MaxHeapSize * (ZFragmentationLimit / 100); } size_t ZHeuristics::significant_young_overhead() { - return MaxHeapSize * ZYoungCompactionLimit; + return MaxHeapSize * (ZYoungCompactionLimit / 100); } diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index 9ccacdc9a3ca1..af97a549b0de3 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -26,11 +26,21 @@ #include "gc/z/zIterator.hpp" +#include "gc/z/zVerify.hpp" #include "memory/iterator.inline.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" inline bool ZIterator::is_invisible_object(oop obj) { + // This is a good place to make sure that we can't concurrently iterate over + // objects while VMThread operations think they have exclusive access to the + // object graph. + // + // One example that have caused problems is the JFR Leak Profiler, which + // sets the mark word to a value that makes the object arrays look like + // invisible objects. + z_verify_safepoints_are_blocked(); + return obj->mark_acquire().is_marked(); } diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.cpp b/src/hotspot/share/gc/z/zReferenceProcessor.cpp index 1037093523dd6..df8cb2b0e959f 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 d39cc8634cd22..7a8900827da83 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/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 60a6616d0a7ec..78efa7cdb12a1 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -87,6 +87,7 @@ ZRelocateQueue::ZRelocateQueue() _nworkers(0), _nsynchronized(0), _synchronize(false), + _is_active(false), _needs_attention(0) {} bool ZRelocateQueue::needs_attention() const { @@ -103,6 +104,20 @@ void ZRelocateQueue::dec_needs_attention() { assert(needs_attention == 0 || needs_attention == 1, "Invalid state"); } +void ZRelocateQueue::activate(uint nworkers) { + _is_active = true; + join(nworkers); +} + +void ZRelocateQueue::deactivate() { + Atomic::store(&_is_active, false); + clear(); +} + +bool ZRelocateQueue::is_active() const { + return Atomic::load(&_is_active); +} + void ZRelocateQueue::join(uint nworkers) { assert(nworkers != 0, "Must request at least one worker"); assert(_nworkers == 0, "Invalid state"); @@ -327,7 +342,7 @@ ZWorkers* ZRelocate::workers() const { } void ZRelocate::start() { - _queue.join(workers()->active_workers()); + _queue.activate(workers()->active_workers()); } void ZRelocate::add_remset(volatile zpointer* p) { @@ -1088,6 +1103,9 @@ class ZRelocateTask : public ZRestartableTask { ~ZRelocateTask() { _generation->stat_relocation()->at_relocate_end(_small_allocator.in_place_count(), _medium_allocator.in_place_count()); + + // Signal that we're not using the queue anymore. Used mostly for asserts. + _queue->deactivate(); } virtual void work() { @@ -1232,8 +1250,6 @@ void ZRelocate::relocate(ZRelocationSet* relocation_set) { ZRelocateAddRemsetForFlipPromoted task(relocation_set->flip_promoted_pages()); workers()->run(&task); } - - _queue.clear(); } ZPageAge ZRelocate::compute_to_age(ZPageAge from_age) { @@ -1316,3 +1332,7 @@ void ZRelocate::desynchronize() { ZRelocateQueue* ZRelocate::queue() { return &_queue; } + +bool ZRelocate::is_queue_active() const { + return _queue.is_active(); +} diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index ed54103d53c18..1b35abdf521fb 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -41,6 +41,7 @@ class ZRelocateQueue { uint _nworkers; uint _nsynchronized; bool _synchronize; + volatile bool _is_active; volatile int _needs_attention; bool needs_attention() const; @@ -53,6 +54,10 @@ class ZRelocateQueue { public: ZRelocateQueue(); + void activate(uint nworkers); + void deactivate(); + bool is_active() const; + void join(uint nworkers); void resize_workers(uint nworkers); void leave(); @@ -99,6 +104,8 @@ class ZRelocate { void desynchronize(); ZRelocateQueue* queue(); + + bool is_queue_active() const; }; #endif // SHARE_GC_Z_ZRELOCATE_HPP diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index 83bdf13b2bb02..92f245777b4e9 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -106,11 +106,16 @@ class ZRelocationSetInstallTask : public ZTask { } virtual void work() { + // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field + SuspendibleThreadSetJoiner sts_joiner; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, _medium->length() + page_index); + + SuspendibleThreadSet::yield(); } // Allocate and install forwardings for medium pages @@ -118,6 +123,8 @@ class ZRelocationSetInstallTask : public ZTask { ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + + SuspendibleThreadSet::yield(); } } diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index 3eb28d3cafe26..a7d39e5ed9cc5 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -29,11 +29,12 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" +#include "gc/z/zBarrier.hpp" #include "oops/oop.hpp" template inline void ZUncoloredRoot::barrier(ObjectFunctionT function, zaddress_unsafe* p, uintptr_t color) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); const zaddress_unsafe addr = Atomic::load(p); assert_is_valid(addr); diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 6950f66915871..c88d7ad7978c9 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -21,7 +21,6 @@ * questions. */ -#include "memory/allocation.hpp" #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" #include "gc/shared/gc_globals.hpp" @@ -37,22 +36,74 @@ #include "gc/z/zStoreBarrierBuffer.inline.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zVerify.hpp" +#include "memory/allocation.hpp" #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.hpp" #include "runtime/frame.inline.hpp" #include "runtime/globals.hpp" #include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" +#include "runtime/javaThread.inline.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stackWatermark.inline.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/preserveException.hpp" #include "utilities/resourceHash.hpp" +#ifdef ASSERT + +// Used to verify that safepoints operations can't be scheduled concurrently +// with callers to this function. Typically used to verify that object oops +// and headers are safe to access. +void z_verify_safepoints_are_blocked() { + Thread* current = Thread::current(); + + if (current->is_ConcurrentGC_thread()) { + assert(current->is_suspendible_thread(), // Thread prevents safepoints + "Safepoints are not blocked by current thread"); + + } else if (current->is_Worker_thread()) { + assert(// Check if ... + // the thread prevents safepoints + current->is_suspendible_thread() || + // the coordinator thread is the safepointing VMThread + current->is_indirectly_safepoint_thread() || + // the coordinator thread prevents safepoints + current->is_indirectly_suspendible_thread() || + // the RelocateQueue prevents safepoints + // + // RelocateQueue acts as a pseudo STS leaver/joiner and blocks + // safepoints. There's currently no infrastructure to check if the + // current thread is active or not, so check the global states instead. + ZGeneration::young()->is_relocate_queue_active() || + ZGeneration::old()->is_relocate_queue_active(), + "Safepoints are not blocked by current thread"); + + } else if (current->is_Java_thread()) { + JavaThreadState state = JavaThread::cast(current)->thread_state(); + assert(state == _thread_in_Java || state == _thread_in_vm || state == _thread_new, + "Safepoints are not blocked by current thread from state: %d", state); + + } else if (current->is_JfrSampler_thread()) { + // The JFR sampler thread blocks out safepoints with this lock. + assert_lock_strong(Threads_lock); + + } else if (current->is_VM_thread()) { + // The VM Thread doesn't schedule new safepoints while executing + // other safepoint or handshake operations. + + } else { + fatal("Unexpected thread type"); + } +} + +#endif + #define BAD_OOP_ARG(o, p) "Bad oop " PTR_FORMAT " found at " PTR_FORMAT, untype(o), p2i(p) static bool z_is_null_relaxed(zpointer o) { diff --git a/src/hotspot/share/gc/z/zVerify.hpp b/src/hotspot/share/gc/z/zVerify.hpp index e9ada2cefa9ca..447d38504a262 100644 --- a/src/hotspot/share/gc/z/zVerify.hpp +++ b/src/hotspot/share/gc/z/zVerify.hpp @@ -30,6 +30,8 @@ class frame; class ZForwarding; class ZPageAllocator; +NOT_DEBUG(inline) void z_verify_safepoints_are_blocked() NOT_DEBUG_RETURN; + class ZVerify : public AllStatic { private: static void roots_strong(bool verify_after_old_mark); diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 45848fb024311..03b47bcd21dc5 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/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 51e41b7740ed6..0648a5e64db2c 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -115,10 +115,10 @@ TRACE_REQUEST_FUNC(JVMInformation) { TRACE_REQUEST_FUNC(OSInformation) { ResourceMark rm; - char* os_name = NEW_RESOURCE_ARRAY(char, 2048); - JfrOSInterface::os_version(&os_name); + char* os_version = nullptr; + JfrOSInterface::os_version(&os_version); EventOSInformation event; - event.set_osVersion(os_name); + event.set_osVersion(os_version); event.commit(); } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 799d6ef899d03..0aed916702e79 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -117,16 +117,16 @@ bool JfrCheckpointManager::initialize_early() { assert(_thread_local_mspace == nullptr, "invariant"); _thread_local_mspace = new JfrThreadLocalCheckpointMspace(); if (_thread_local_mspace == nullptr || !_thread_local_mspace->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 f99159b3a51c9..a8ec2fd70f538 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 94ac07729697e..3a86f204e619d 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,113 @@ 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"; - } - assert(false, "invalid type array klass"); - return nullptr; +template +static traceid artifact_id(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return JfrTraceId::load_raw(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; +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); } - 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; + if (not_used(ptr)) { + SET_TRANSIENT(ptr); + } + assert(used(ptr), "invariant"); + return artifact_id(ptr); } -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 (klass->is_objArray_klass()) { + klass = ObjArrayKlass::cast(klass)->bottom_klass(); } - if (leakp) { - SET_LEAKP(pkg_entry); + return klass->is_non_strong_hidden() ? nullptr : klass->class_loader_data(); +} + +static inline bool should_do_cld_klass(const Klass* cld_klass, bool leakp) { + return cld_klass != nullptr && _artifacts->should_do_cld_klass(cld_klass, leakp); +} + +static inline bool should_enqueue(const Klass* cld_klass) { + assert(cld_klass != nullptr, "invariant"); + if (previous_epoch()) { + return false; + } + CldPtr cld = get_cld(cld_klass); + return cld != nullptr && !cld->is_unloading(); +} + +static inline KlassPtr get_cld_klass(CldPtr cld, bool leakp) { + if (cld == nullptr) { + return nullptr; } - // package implicitly tagged already - return artifact_id(pkg_entry); + assert(leakp ? IS_LEAKP(cld) : used(cld), "invariant"); + KlassPtr cld_klass = cld->class_loader_klass(); + if (!should_do_cld_klass(cld_klass, leakp)) { + return nullptr; + } + if (should_enqueue(cld_klass)) { + // 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; +} + +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_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; } - return artifact_id(module_entry); + // 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 +227,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 +238,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 +456,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 +528,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 +563,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 +596,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 +704,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 +808,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 +816,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 +945,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 +984,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 +1004,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 +1031,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 +1094,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 +1115,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 +1143,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 +1165,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 +1229,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 +1247,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 0876281d53f6b..883821f853c0a 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 b0c2d989de52e..24424fdef3aa9 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 e5b9a33ef56a3..13853e14a1334 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 40c3d7a8c4f4d..cc460f8c2aad6 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 3e2541fad98ef..9f4969b01872a 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 09a452caaa589..49ced300e5591 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 a36b85dbb7eb1..5f5c87d239c7f 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/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 50d8b6041b674..75bc3d9af7216 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -45,8 +45,6 @@ // Forward declarations. class OopClosure; -class FilteringClosure; - class PSPromotionManager; class ParCompactionManager; diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 305501bfb1467..1b92193300449 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) { @@ -790,6 +806,13 @@ Node* OrINode::Ideal(PhaseGVN* phase, bool can_reshape) { return new RotateRightNode(in(1)->in(1), shift, TypeInt::INT); } } + + // Convert "~a | ~b" into "~(a & b)" + if (AddNode::is_not(phase, in(1), T_INT) && AddNode::is_not(phase, in(2), T_INT)) { + Node* and_a_b = new AndINode(in(1)->in(1), in(2)->in(1)); + Node* tn = phase->transform(and_a_b); + return AddNode::make_not(phase, tn, T_INT); + } return nullptr; } @@ -856,6 +879,14 @@ Node* OrLNode::Ideal(PhaseGVN* phase, bool can_reshape) { return new RotateRightNode(in(1)->in(1), shift, TypeLong::LONG); } } + + // Convert "~a | ~b" into "~(a & b)" + if (AddNode::is_not(phase, in(1), T_LONG) && AddNode::is_not(phase, in(2), T_LONG)) { + Node* and_a_b = new AndLNode(in(1)->in(1), in(2)->in(1)); + Node* tn = phase->transform(and_a_b); + return AddNode::make_not(phase, tn, T_LONG); + } + return nullptr; } diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 709958b6abf25..577dd6ba29588 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 97267bdfe1d83..c4f7906faba46 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) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index ba383a679e182..b7c761d9b9845 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"); diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index fd0d96cc79a2c..0b1a6af12f50c 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -281,6 +281,15 @@ void CastIINode::dump_spec(outputStream* st) const { } #endif +CastIINode* CastIINode::pin_array_access_node() const { + assert(_dependency == RegularDependency, "already pinned"); + if (has_range_check()) { + return new CastIINode(in(0), in(1), bottom_type(), StrongDependency, has_range_check()); + } + return nullptr; +} + + const Type* CastLLNode::Value(PhaseGVN* phase) const { const Type* res = ConstraintCastNode::Value(phase); if (res == Type::TOP) { diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 32db08cb74829..3214dd22ad556 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -114,7 +114,7 @@ class CastIINode: public ConstraintCastNode { virtual Node* Identity(PhaseGVN* phase); virtual const Type* Value(PhaseGVN* phase) const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - bool has_range_check() { + bool has_range_check() const { #ifdef _LP64 return _range_check_dependency; #else @@ -123,6 +123,8 @@ class CastIINode: public ConstraintCastNode { #endif } + CastIINode* pin_array_access_node() const; + #ifndef PRODUCT virtual void dump_spec(outputStream* st) const; #endif diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index bc6f181aa0755..d72e9bce21381 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -430,8 +430,8 @@ class IfNode : public MultiBranchNode { virtual const RegMask &out_RegMask() const; Node* fold_compares(PhaseIterGVN* phase); static Node* up_one_dom(Node* curr, bool linear_only = false); - Node* dominated_by(Node* prev_dom, PhaseIterGVN* igvn); bool is_zero_trip_guard() const; + Node* dominated_by(Node* prev_dom, PhaseIterGVN* igvn, bool pin_array_access_nodes); // Takes the type of val and filters it through the test represented // by if_proj and returns a more refined type if one is produced. @@ -505,6 +505,8 @@ class IfProjNode : public CProjNode { IfProjNode(IfNode *ifnode, uint idx) : CProjNode(ifnode,idx) {} virtual Node* Identity(PhaseGVN* phase); + void pin_array_access_nodes(PhaseIterGVN* igvn); + protected: // Type of If input when this branch is always taken virtual bool always_taken(const TypeTuple* t) const = 0; diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 2f13a8bbd5721..97c45f508445e 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/classes.hpp b/src/hotspot/share/opto/classes.hpp index 7d1a2cd1db0e8..f1da18f464e46 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 @@ -449,6 +449,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 429d751d2bc3c..47f5fc3a6db3c 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -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" @@ -637,6 +639,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), @@ -931,6 +934,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), @@ -994,6 +998,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) { @@ -1061,7 +1070,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 && @@ -3703,6 +3712,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: @@ -4363,6 +4397,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())) { diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index d4e4e3fd71859..dc37399338cf3 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -54,6 +54,7 @@ class Bundle; class CallGenerator; class CallStaticJavaNode; class CloneMap; +class CompilationFailureInfo; class ConnectionGraph; class IdealGraphPrinter; class InlineTree; @@ -368,6 +369,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. @@ -821,6 +823,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); @@ -1137,9 +1140,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/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 2751e8912624f..a931c4de1f40d 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -539,7 +539,7 @@ int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) { //------------------------------adjust_check----------------------------------- // Adjust (widen) a prior range check -static void adjust_check(Node* proj, Node* range, Node* index, +static void adjust_check(IfProjNode* proj, Node* range, Node* index, int flip, jint off_lo, PhaseIterGVN* igvn) { PhaseGVN *gvn = igvn; // Break apart the old check @@ -547,25 +547,31 @@ static void adjust_check(Node* proj, Node* range, Node* index, Node *bol = iff->in(1); if( bol->is_top() ) return; // In case a partially dead range check appears // bail (or bomb[ASSERT/DEBUG]) if NOT projection-->IfNode-->BoolNode - DEBUG_ONLY( if( !bol->is_Bool() ) { proj->dump(3); fatal("Expect projection-->IfNode-->BoolNode"); } ) - if( !bol->is_Bool() ) return; + DEBUG_ONLY( if (!bol->is_Bool()) { proj->dump(3); fatal("Expect projection-->IfNode-->BoolNode"); } ) + if (!bol->is_Bool()) return; Node *cmp = bol->in(1); // Compute a new check Node *new_add = gvn->intcon(off_lo); - if( index ) { - new_add = off_lo ? gvn->transform(new AddINode( index, new_add )) : index; + if (index) { + new_add = off_lo ? gvn->transform(new AddINode(index, new_add)) : index; } Node *new_cmp = (flip == 1) - ? new CmpUNode( new_add, range ) - : new CmpUNode( range, new_add ); + ? new CmpUNode(new_add, range) + : new CmpUNode(range, new_add); new_cmp = gvn->transform(new_cmp); // See if no need to adjust the existing check - if( new_cmp == cmp ) return; + if (new_cmp == cmp) return; // Else, adjust existing check - Node *new_bol = gvn->transform( new BoolNode( new_cmp, bol->as_Bool()->_test._test ) ); - igvn->rehash_node_delayed( iff ); - iff->set_req_X( 1, new_bol, igvn ); + Node* new_bol = gvn->transform(new BoolNode(new_cmp, bol->as_Bool()->_test._test)); + igvn->rehash_node_delayed(iff); + iff->set_req_X(1, new_bol, igvn); + // As part of range check smearing, this range check is widened. Loads and range check Cast nodes that are control + // dependent on this range check now depend on multiple dominating range checks. These control dependent nodes end up + // at the lowest/nearest dominating check in the graph. To ensure that these Loads/Casts do not float above any of the + // dominating checks (even when the lowest dominating check is later replaced by yet another dominating check), we + // need to pin them at the lowest dominating check. + proj->pin_array_access_nodes(igvn); } //------------------------------up_one_dom------------------------------------- @@ -1418,7 +1424,7 @@ static Node *remove_useless_bool(IfNode *iff, PhaseGVN *phase) { static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff); struct RangeCheck { - Node* ctl; + IfProjNode* ctl; jint off; }; @@ -1486,14 +1492,14 @@ Node* IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (prev_dom != nullptr) { // Replace dominated IfNode - return dominated_by(prev_dom, igvn); + return dominated_by(prev_dom, igvn, false); } return simple_subsuming(igvn); } //------------------------------dominated_by----------------------------------- -Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { +Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN* igvn, bool pin_array_access_nodes) { #ifndef PRODUCT if (TraceIterativeGVN) { tty->print(" Removing IfNode: "); this->dump(); @@ -1506,15 +1512,6 @@ Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { int prev_op = prev_dom->Opcode(); Node *top = igvn->C->top(); // Shortcut to top - // Loop predicates may have depending checks which should not - // be skipped. For example, range check predicate has two checks - // for lower and upper bounds. - ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != nullptr || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_profile_predicate) != nullptr) { - prev_dom = idom; - } - // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses. for (DUIterator_Last imin, i = last_outs(imin); i >= imin; --i) { @@ -1537,6 +1534,19 @@ Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { // For control producers. // Do not rewire Div and Mod nodes which could have a zero divisor to avoid skipping their zero check. igvn->replace_input_of(s, 0, data_target); // Move child to data-target + if (pin_array_access_nodes && data_target != top) { + // As a result of range check smearing, Loads and range check Cast nodes that are control dependent on this + // range check (that is about to be removed) now depend on multiple dominating range checks. After the removal + // of this range check, these control dependent nodes end up at the lowest/nearest dominating check in the + // graph. To ensure that these Loads/Casts do not float above any of the dominating checks (even when the + // lowest dominating check is later replaced by yet another dominating check), we need to pin them at the + // lowest dominating check. + Node* clone = s->pin_array_access_node(); + if (clone != nullptr) { + clone = igvn->transform(clone); + igvn->replace_node(s, clone); + } + } } else { // Find the control input matching this def-use edge. // For Regions it may not be in slot 0. @@ -1781,6 +1791,22 @@ bool IfNode::is_zero_trip_guard() const { return false; } +void IfProjNode::pin_array_access_nodes(PhaseIterGVN* igvn) { + for (DUIterator i = outs(); has_out(i); i++) { + Node* u = out(i); + if (!u->depends_only_on_test()) { + continue; + } + Node* clone = u->pin_array_access_node(); + if (clone != nullptr) { + clone = igvn->transform(clone); + assert(clone != u, "shouldn't common"); + igvn->replace_node(u, clone); + --i; + } + } +} + #ifndef PRODUCT //------------------------------dump_spec-------------------------------------- void IfNode::dump_spec(outputStream *st) const { @@ -1910,7 +1936,7 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { off_lo = MIN2(off_lo,offset2); off_hi = MAX2(off_hi,offset2); // Record top NRC range checks - prev_checks[nb_checks%NRC].ctl = prev_dom; + prev_checks[nb_checks%NRC].ctl = prev_dom->as_IfProj(); prev_checks[nb_checks%NRC].off = offset2; nb_checks++; } @@ -1927,6 +1953,15 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // the interpreter. If we see range-check deopt's, do not widen! if (!phase->C->allow_range_check_smearing()) return nullptr; + if (can_reshape && !phase->C->post_loop_opts_phase()) { + // We are about to perform range check smearing (i.e. remove this RangeCheck if it is dominated by + // a series of RangeChecks which have a range that covers this RangeCheck). This can cause array access nodes to + // be pinned. We want to avoid that and first allow range check elimination a chance to remove the RangeChecks + // from loops. Hence, we delay range check smearing until after loop opts. + phase->C->record_for_post_loop_opts_igvn(this); + return nullptr; + } + // Didn't find prior covering check, so cannot remove anything. if (nb_checks == 0) { return nullptr; @@ -2000,6 +2035,26 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Test is now covered by prior checks, dominate it out prev_dom = rc0.ctl; } + // The last RangeCheck is found to be redundant with a sequence of n (n >= 2) preceding RangeChecks. + // If an array load is control dependent on the eliminated range check, the array load nodes (CastII and Load) + // become control dependent on the last range check of the sequence, but they are really dependent on the entire + // sequence of RangeChecks. If RangeCheck#n is later replaced by a dominating identical check, the array load + // nodes must not float above the n-1 other RangeCheck in the sequence. We pin the array load nodes here to + // guarantee it doesn't happen. + // + // RangeCheck#1 RangeCheck#1 + // | \ | \ + // | uncommon trap | uncommon trap + // .. .. + // RangeCheck#n -> RangeCheck#n + // | \ | \ + // | uncommon trap CastII uncommon trap + // RangeCheck Load + // | \ + // CastII uncommon trap + // Load + + return dominated_by(prev_dom, igvn, true); } } else { prev_dom = search_identical(4, igvn); @@ -2010,7 +2065,7 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { } // Replace dominated IfNode - return dominated_by(prev_dom, igvn); + return dominated_by(prev_dom, igvn, false); } ParsePredicateNode::ParsePredicateNode(Node* control, Deoptimization::DeoptReason deopt_reason, PhaseGVN* gvn) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 2bc1cc261c6c6..6bb3e16475a56 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4572,14 +4572,22 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { Node* no_ctrl = nullptr; Node* header = make_load(no_ctrl, header_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); - // Test the header to see if it is unlocked. + // Test the header to see if it is safe to read w.r.t. locking. Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); - Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); - Node *chk_unlocked = _gvn.transform(new CmpXNode( lmasked_header, unlocked_val)); - Node *test_unlocked = _gvn.transform(new BoolNode( chk_unlocked, BoolTest::ne)); + if (LockingMode == LM_LIGHTWEIGHT) { + Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); + Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); + Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); - generate_slow_guard(test_unlocked, slow_region); + generate_slow_guard(test_monitor, slow_region); + } else { + Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); + Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); + Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); + + generate_slow_guard(test_not_unlocked, slow_region); + } // Get the hash value and check to see that it has been properly assigned. // We depend on hash_mask being at most 32 bits and avoid the use of diff --git a/src/hotspot/share/opto/locknode.cpp b/src/hotspot/share/opto/locknode.cpp index fa80c885d3c86..965b8071897c1 100644 --- a/src/hotspot/share/opto/locknode.cpp +++ b/src/hotspot/share/opto/locknode.cpp @@ -179,8 +179,6 @@ void FastLockNode::create_rtm_lock_counter(JVMState* state) { void Parse::do_monitor_enter() { kill_dead_locals(); - C->set_has_monitors(true); - // Null check; get casted pointer. Node* obj = null_check(peek()); // Check for locking null object diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 6a8efb0872a5b..95496d73d56c4 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -1180,6 +1180,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod return false; } BoolNode* bol = test->as_Bool(); + bool range_check_predicate = false; if (invar.is_invariant(bol)) { C->print_method(PHASE_BEFORE_LOOP_PREDICATION_IC, 4, iff); // Invariant test @@ -1212,6 +1213,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))) { + range_check_predicate = true; 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"); @@ -1294,7 +1296,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod invar.map_ctrl(if_success_proj, new_predicate_proj); // so that invariance test can be appropriate // Eliminate the old If in the loop body - dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con); + // If a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2 + // Hoisted Check Predicates (one for the start of the loop, one for the end) but we can only keep track of one control + // dependency: pin the data dependent nodes. + dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con, range_check_predicate); C->set_major_progress(); return true; diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index 87c71bf16ffd5..ae657b55fbb23 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -179,12 +179,12 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) { // Hardwire the control paths in the loops into if(true) and if(false) _igvn.rehash_node_delayed(unswitch_iff); - dominated_by(proj_true->as_IfProj(), unswitch_iff, false, false); + dominated_by(proj_true->as_IfProj(), unswitch_iff); IfNode* unswitch_iff_clone = old_new[unswitch_iff->_idx]->as_If(); _igvn.rehash_node_delayed(unswitch_iff_clone); ProjNode* proj_false = invar_iff->proj_out(0); - dominated_by(proj_false->as_IfProj(), unswitch_iff_clone, false, false); + dominated_by(proj_false->as_IfProj(), unswitch_iff_clone); // Reoptimize loops loop->record_for_igvn(); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 4a34d7e49baca..068ca07e1299c 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1507,7 +1507,7 @@ class PhaseIdealLoop : public PhaseTransform { Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). - void dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip = false, bool exclude_loop_predicate = false); + void dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip = false, bool pin_array_access_nodes = false); // Split Node 'n' through merge point RegionNode* split_thru_region(Node* n, RegionNode* region); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index b92d541ba88d7..80a3d1a072b37 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -287,7 +287,11 @@ bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) co return false; } - assert(n->in(0) == nullptr, "divisions with zero check should already have bailed out earlier in split-if"); + if (n->in(0) != nullptr) { + // Cannot split through phi if Div or Mod node has a control dependency to a zero check. + return true; + } + Node* divisor = n->in(2); return is_divisor_counted_loop_phi(divisor, region) && loop_phi_backedge_type_contains_zero(divisor, zero); @@ -305,7 +309,7 @@ bool PhaseIdealLoop::loop_phi_backedge_type_contains_zero(const Node* phi_diviso // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the // live path up to the dominating control. -void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, bool exclude_loop_predicate) { +void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, bool pin_array_access_nodes) { if (VerifyLoopOptimizations && PrintOpto) { tty->print_cr("dominating test"); } // prevdom is the dominating projection of the dominating test. @@ -330,7 +334,7 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b // Hack the dominated test _igvn.replace_input_of(iff, 1, con); - // If I dont have a reachable TRUE and FALSE path following the IfNode then + // If I don't have a reachable TRUE and FALSE path following the IfNode then // I can assume this path reaches an infinite loop. In this case it's not // important to optimize the data Nodes - either the whole compilation will // be tossed or this path (and all data Nodes) will go dead. @@ -341,24 +345,9 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b // dominating projection. Node* dp = iff->proj_out_or_null(pop == Op_IfTrue); - // Loop predicates may have depending checks which should not - // be skipped. For example, range check predicate has two checks - // for lower and upper bounds. if (dp == nullptr) return; - ProjNode* dp_proj = dp->as_Proj(); - ProjNode* unc_proj = iff->proj_out(1 - dp_proj->_con)->as_Proj(); - if (exclude_loop_predicate && - (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != nullptr || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_profile_predicate) != nullptr || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check) != nullptr)) { - // If this is a range check (IfNode::is_range_check), do not - // reorder because Compile::allow_range_check_smearing might have - // changed the check. - return; // Let IGVN transformation change control dependence. - } - IdealLoopTree* old_loop = get_loop(dp); for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { @@ -367,6 +356,20 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b if (cd->depends_only_on_test() && _igvn.no_dependent_zero_check(cd)) { assert(cd->in(0) == dp, ""); _igvn.replace_input_of(cd, 0, prevdom); + if (pin_array_access_nodes) { + // Because of Loop Predication, Loads and range check Cast nodes that are control dependent on this range + // check (that is about to be removed) now depend on multiple dominating Hoisted Check Predicates. After the + // removal of this range check, these control dependent nodes end up at the lowest/nearest dominating predicate + // in the graph. To ensure that these Loads/Casts do not float above any of the dominating checks (even when the + // lowest dominating check is later replaced by yet another dominating check), we need to pin them at the lowest + // dominating check. + Node* clone = cd->pin_array_access_node(); + if (clone != nullptr) { + clone = _igvn.register_new_node_with_optimizer(clone, cd); + _igvn.replace_node(cd, clone); + cd = clone; + } + } set_early_ctrl(cd, false); IdealLoopTree* new_loop = get_loop(get_ctrl(cd)); if (old_loop != new_loop) { @@ -1486,7 +1489,7 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { // Replace the dominated test with an obvious true or false. // Place it on the IGVN worklist for later cleanup. C->set_major_progress(); - dominated_by(prevdom->as_IfProj(), n->as_If(), false, true); + dominated_by(prevdom->as_IfProj(), n->as_If()); DEBUG_ONLY( if (VerifyLoopOptimizations) { verify(); } ); return; } @@ -1579,10 +1582,10 @@ bool PhaseIdealLoop::try_merge_identical_ifs(Node* n) { // unrelated control dependency. for (uint i = 1; i < new_false_region->req(); i++) { if (is_dominator(dom_proj_true, new_false_region->in(i))) { - dominated_by(dom_proj_true->as_IfProj(), new_false_region->in(i)->in(0)->as_If(), false, false); + dominated_by(dom_proj_true->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); } else { assert(is_dominator(dom_proj_false, new_false_region->in(i)), "bad if"); - dominated_by(dom_proj_false->as_IfProj(), new_false_region->in(i)->in(0)->as_If(), false, false); + dominated_by(dom_proj_false->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); } } return true; diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index 61042dfe71eff..173a38fa9d854 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/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 4f2110bfb4cd0..50eaac1c8d089 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -845,8 +845,12 @@ bool LoadNode::can_remove_control() const { return !has_pinned_control_dependency(); } uint LoadNode::size_of() const { return sizeof(*this); } -bool LoadNode::cmp( const Node &n ) const -{ return !Type::cmp( _type, ((LoadNode&)n)._type ); } +bool LoadNode::cmp(const Node &n) const { + LoadNode& load = (LoadNode &)n; + return !Type::cmp(_type, load._type) && + _control_dependency == load._control_dependency && + _mo == load._mo; +} const Type *LoadNode::bottom_type() const { return _type; } uint LoadNode::ideal_reg() const { return _type->ideal_reg(); @@ -983,6 +987,14 @@ static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, return false; } +LoadNode* LoadNode::pin_array_access_node() const { + const TypePtr* adr_type = this->adr_type(); + if (adr_type != nullptr && adr_type->isa_aryptr()) { + return clone_pinned(); + } + return nullptr; +} + // Is the value loaded previously stored by an arraycopy? If so return // a load node that reads from the source array so we may be able to // optimize out the ArrayCopy node later. @@ -1002,7 +1014,8 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { return nullptr; } - LoadNode* ld = clone()->as_Load(); + // load depends on the tests that validate the arraycopy + LoadNode* ld = clone_pinned(); Node* addp = in(MemNode::Address)->clone(); if (ac->as_ArrayCopy()->is_clonebasic()) { assert(ld_alloc != nullptr, "need an alloc"); @@ -1044,8 +1057,6 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { ld->set_req(MemNode::Address, addp); ld->set_req(0, ctl); ld->set_req(MemNode::Memory, mem); - // load depends on the tests that validate the arraycopy - ld->_control_dependency = UnknownControl; return ld; } return nullptr; @@ -2499,6 +2510,12 @@ Node* LoadNode::klass_identity_common(PhaseGVN* phase) { return this; } +LoadNode* LoadNode::clone_pinned() const { + LoadNode* ld = clone()->as_Load(); + ld->_control_dependency = UnknownControl; + return ld; +} + //------------------------------Value------------------------------------------ const Type* LoadNKlassNode::Value(PhaseGVN* phase) const { diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 3a521c8f63365..c7fa14cb96de7 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -292,6 +292,8 @@ class LoadNode : public MemNode { bool has_unknown_control_dependency() const { return _control_dependency == UnknownControl; } bool has_pinned_control_dependency() const { return _control_dependency == Pinned; } + LoadNode* pin_array_access_node() const; + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -317,6 +319,8 @@ class LoadNode : public MemNode { virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM && _control_dependency == DependsOnlyOnTest; } + + LoadNode* clone_pinned() const; }; //------------------------------LoadBNode-------------------------------------- diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 3b493b5efa277..8b7fa22af55a7 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 @@ -610,6 +610,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); @@ -750,6 +757,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 7e9c5196942fb..1b80458d3c36d 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -178,6 +178,7 @@ class StoreVectorMaskedNode; class LoadVectorGatherNode; class StoreVectorNode; class StoreVectorScatterNode; +class VerifyVectorAlignmentNode; class VectorMaskCmpNode; class VectorUnboxNode; class VectorSet; @@ -1135,7 +1136,14 @@ class Node { template void visit_uses(Callback callback, Check is_boundary) const; -//----------------- Code Generation + // Returns a clone of the current node that's pinned (if the current node is not) for nodes found in array accesses + // (Load and range check CastII nodes). + // This is used when an array access is made dependent on 2 or more range checks (range check smearing or Loop Predication). + virtual Node* pin_array_access_node() const { + return nullptr; + } + + //----------------- Code Generation // Ideal register class for Matching. Zero means unmatched instruction // (these are cloned instead of converted to machine nodes). diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 64d98f27ff614..9481b91ce39e9 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.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 @@ -775,7 +775,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, SafePointScalarMergeNode* smerge = local->as_SafePointScalarMerge(); ObjectMergeValue* mv = (ObjectMergeValue*) sv_for_node_id(objs, smerge->_idx); - if (mv == NULL) { + if (mv == nullptr) { GrowableArray deps; int merge_pointer_idx = smerge->merge_pointer_idx(sfpt->jvms()); @@ -783,7 +783,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, assert(deps.length() == 1, "missing value"); int selector_idx = smerge->selector_idx(sfpt->jvms()); - (void)FillLocArray(1, NULL, sfpt->in(selector_idx), &deps, NULL); + (void)FillLocArray(1, nullptr, sfpt->in(selector_idx), &deps, nullptr); assert(deps.length() == 2, "missing value"); mv = new ObjectMergeValue(smerge->_idx, deps.at(0), deps.at(1)); @@ -1085,6 +1085,30 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { } scval = sv; } + } else if (obj_node->is_SafePointScalarMerge()) { + SafePointScalarMergeNode* smerge = obj_node->as_SafePointScalarMerge(); + ObjectMergeValue* mv = (ObjectMergeValue*) sv_for_node_id(objs, smerge->_idx); + + if (mv == nullptr) { + GrowableArray deps; + + int merge_pointer_idx = smerge->merge_pointer_idx(youngest_jvms); + FillLocArray(0, sfn, sfn->in(merge_pointer_idx), &deps, objs); + assert(deps.length() == 1, "missing value"); + + int selector_idx = smerge->selector_idx(youngest_jvms); + FillLocArray(1, nullptr, sfn->in(selector_idx), &deps, nullptr); + assert(deps.length() == 2, "missing value"); + + mv = new ObjectMergeValue(smerge->_idx, deps.at(0), deps.at(1)); + set_sv_for_object_node(objs, mv); + + for (uint i = 1; i < smerge->req(); i++) { + Node* obj_node = smerge->in(i); + FillLocArray(mv->possible_objects()->length(), sfn, obj_node, mv->possible_objects(), objs); + } + } + scval = mv; } else if (!obj_node->is_Con()) { OptoReg::Name obj_reg = C->regalloc()->get_reg_first(obj_node); if( obj_node->bottom_type()->base() == Type::NarrowOop ) { diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index c1a414c01c98c..d8470b9c67bfa 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -449,8 +449,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 b4919043f52ff..ebe81d9b3e802 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -406,19 +406,17 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, PEAS _wrote_stable = false; _wrote_fields = false; _alloc_with_final = nullptr; - _entry_bci = InvocationEntryBci; - _tf = nullptr; _block = nullptr; _first_return = 0; _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; @@ -434,27 +432,11 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, PEAS 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 (Verbose && !CITraceTypeFlow) { - _flow->rpo_print_on(tty); - } - - 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) { @@ -522,14 +504,25 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, PEAS // 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()) { - 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()) { + 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(); @@ -537,8 +530,6 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, PEAS } } #endif - } - _tf = C->tf(); // the OSR entry type is different } #ifdef ASSERT @@ -550,6 +541,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, PEAS #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) @@ -1602,13 +1597,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"); diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 655434c4f4b90..3356498ce13f7 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -22,16 +22,15 @@ * */ -#include "opto/addnode.hpp" -#include "opto/node.hpp" #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/loopnode.hpp" #include "opto/movenode.hpp" +#include "opto/node.hpp" #include "opto/opaquenode.hpp" - //------------------------------split_thru_region------------------------------ // Split Node 'n' through merge point. RegionNode* PhaseIdealLoop::split_thru_region(Node* n, RegionNode* region) { diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index 1011cb54245f3..393585d453cfd 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -43,18 +43,6 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const if (!superklass->is_interface() && superklass->is_abstract() && !superklass->as_instance_klass()->has_subklass()) { Compile::current()->dependencies()->assert_leaf_type(superklass); - if (subk->is_same_java_type_as(superk) && !sub_t->maybe_null()) { - // The super_t has no subclasses, and sub_t has the same type and is not null, - // hence the check should always evaluate to EQ. However, this is an impossible - // situation since super_t is also abstract, and hence sub_t cannot have the - // same type and be non-null. - // Still, if the non-static method of an abstract class without subclasses is - // force-compiled, the Param0 has the self/this pointer with NotNull. This - // method would now never be called, because of the leaf-type dependency. Hence, - // just for consistency with verification, we return EQ. - return TypeInt::CC_EQ; - } - // subk is either a supertype of superk, or null. In either case, superk is a subtype. return TypeInt::CC_GT; } } diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index c3f0a60af20ff..b1d1169f3571c 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-------------------------- @@ -2493,9 +2397,7 @@ bool SuperWord::output() { #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++) { @@ -2768,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)); @@ -3515,23 +3428,21 @@ void SuperWord::remove_pack_at(int pos) { void SuperWord::packset_sort(int n) { // simple bubble sort so that we capitalize with O(n) when its already sorted - while (n != 0) { - bool swapped = false; + do { + int max_swap_index = 0; for (int i = 1; i < n; i++) { Node_List* q_low = _packset.at(i-1); Node_List* q_i = _packset.at(i); // only swap when we find something to swap if (alignment(q_low->at(0)) > alignment(q_i->at(0))) { - Node_List* t = q_i; *(_packset.adr_at(i)) = q_low; *(_packset.adr_at(i-1)) = q_i; - swapped = true; + max_swap_index = i; } } - if (swapped == false) break; - n--; - } + n = max_swap_index; + } while (n > 1); } LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { @@ -3553,167 +3464,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 2319636c99abc..db7101b26cb53 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/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 7158f40092928..4794140ab0e45 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 8df5d0c9a821f..8e63b40d5ac48 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 6992f3516aac8..e4d3d013cd384 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/jni.cpp b/src/hotspot/share/prims/jni.cpp index 33dcfb6c3fe5e..b6a4443a8c763 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -930,6 +930,11 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive } } + if (selected_method->is_abstract()) { + ResourceMark rm(THREAD); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), selected_method->name()->as_C_string()); + } + methodHandle method(THREAD, selected_method); // Create object to hold arguments for the JavaCall, and associate it with diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp index 7e2f14ead3cc9..1231fd5019fdc 100644 --- a/src/hotspot/share/prims/jvmtiAgent.cpp +++ b/src/hotspot/share/prims/jvmtiAgent.cpp @@ -75,10 +75,6 @@ JvmtiAgent::JvmtiAgent(const char* name, const char* options, bool is_absolute_p _options(copy_string(options)), _os_lib(nullptr), _os_lib_path(nullptr), -#ifdef AIX - _inode(0), - _device(0), -#endif _jplis(nullptr), _loaded(false), _absolute_path(is_absolute_path), @@ -123,24 +119,6 @@ const char* JvmtiAgent::os_lib_path() const { return _os_lib_path; } -#ifdef AIX -void JvmtiAgent::set_inode(ino64_t inode) { - _inode = inode; -} - -void JvmtiAgent::set_device(dev64_t device) { - _device = device; -} - -ino64_t JvmtiAgent::inode() const { - return _inode; -} - -dev64_t JvmtiAgent::device() const { - return _device; -} -#endif - bool JvmtiAgent::is_loaded() const { return _loaded; } @@ -295,20 +273,6 @@ static bool load_agent_from_executable(JvmtiAgent* agent, const char* on_load_sy return os::find_builtin_agent(agent, &on_load_symbols[0], num_symbol_entries); } -#ifdef AIX -// save the inode and device of the library's file as a signature. This signature can be used -// in the same way as the library handle as a signature on other platforms. -static void save_library_signature(JvmtiAgent* agent, const char* name) { - struct stat64x libstat; - if (0 == os::Aix::stat64x_via_LIBPATH(name, &libstat)) { - agent->set_inode(libstat.st_ino); - agent->set_device(libstat.st_dev); - } else { - assert(false, "stat64x failed"); - } -} -#endif - // Load the library from the absolute path of the agent, if available. static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_error) { DEBUG_ONLY(assert_preload(agent);) @@ -318,7 +282,6 @@ static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_er if (library == nullptr && vm_exit_on_error) { vm_exit(agent, " in absolute path, with error: ", nullptr); } - AIX_ONLY(if (library != nullptr) save_library_signature(agent, agent->name());) return library; } @@ -331,13 +294,11 @@ static void* load_agent_from_relative_path(JvmtiAgent* agent, bool vm_exit_on_er // Try to load the agent from the standard dll directory if (os::dll_locate_lib(&buffer[0], sizeof buffer, Arguments::get_dll_dir(), name)) { library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf); - AIX_ONLY(if (library != nullptr) save_library_signature(agent, &buffer[0]);) } if (library == nullptr && os::dll_build_name(&buffer[0], sizeof buffer, name)) { // Try the library path directory. library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf); if (library != nullptr) { - AIX_ONLY(save_library_signature(agent, &buffer[0]);) return library; } if (vm_exit_on_error) { @@ -555,11 +516,7 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) { agent->set_os_lib_path(&buffer[0]); agent->set_os_lib(library); agent->set_loaded(); - #ifdef AIX - previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(agent->device(), agent->inode()); - #else previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(library); - #endif } // Print warning if agent was not previously loaded and EnableDynamicAgentLoading not enabled on the command line. diff --git a/src/hotspot/share/prims/jvmtiAgent.hpp b/src/hotspot/share/prims/jvmtiAgent.hpp index 95e910354e654..9baf66988683b 100644 --- a/src/hotspot/share/prims/jvmtiAgent.hpp +++ b/src/hotspot/share/prims/jvmtiAgent.hpp @@ -43,10 +43,6 @@ class JvmtiAgent : public CHeapObj { const char* _options; void* _os_lib; const char* _os_lib_path; -#ifdef AIX - ino64_t _inode; - dev64_t _device; -#endif const void* _jplis; bool _loaded; bool _absolute_path; @@ -84,12 +80,6 @@ class JvmtiAgent : public CHeapObj { void initialization_end(); const Ticks& initialization_time() const; const Tickspan& initialization_duration() const; -#ifdef AIX - void set_inode(ino64_t inode); - void set_device(dev64_t device); - unsigned long inode() const; - unsigned long device() const; -#endif bool load(outputStream* st = nullptr); void unload(); diff --git a/src/hotspot/share/prims/jvmtiAgentList.cpp b/src/hotspot/share/prims/jvmtiAgentList.cpp index b7312b9b75e64..a32eeb7076c09 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.cpp +++ b/src/hotspot/share/prims/jvmtiAgentList.cpp @@ -243,19 +243,6 @@ bool JvmtiAgentList::is_dynamic_lib_loaded(void* os_lib) { } return false; } -#ifdef AIX -bool JvmtiAgentList::is_dynamic_lib_loaded(dev64_t device, ino64_t inode) { - JvmtiAgentList::Iterator it = JvmtiAgentList::agents(); - while (it.has_next()) { - JvmtiAgent* const agent = it.next(); - if (!agent->is_static_lib() && device != 0 && inode != 0 && - agent->device() == device && agent->inode() == inode) { - return true; - } - } - return false; -} -#endif static bool match(JvmtiEnv* env, const JvmtiAgent* agent, const void* os_module_address) { assert(env != nullptr, "invariant"); diff --git a/src/hotspot/share/prims/jvmtiAgentList.hpp b/src/hotspot/share/prims/jvmtiAgentList.hpp index 95dad006ec3ef..cf698c69c01fe 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.hpp +++ b/src/hotspot/share/prims/jvmtiAgentList.hpp @@ -78,9 +78,6 @@ class JvmtiAgentList : AllStatic { static bool is_static_lib_loaded(const char* name); static bool is_dynamic_lib_loaded(void* os_lib); -#ifdef AIX - static bool is_dynamic_lib_loaded(dev64_t device, ino64_t inode); -#endif static JvmtiAgent* lookup(JvmtiEnv* env, void* f_ptr); diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index e02820a2beb7d..c3f1fcac52ff7 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.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 @@ -2896,26 +2896,20 @@ JvmtiEnv::GetClassFields(oop k_mirror, jint* field_count_ptr, jfieldID** fields_ return JVMTI_ERROR_NONE; } - InstanceKlass* ik = InstanceKlass::cast(k); - int result_count = 0; - // First, count the fields. - FilteredFieldStream flds(ik, true, true); - result_count = flds.field_count(); + FilteredJavaFieldStream flds(ik); - // Allocate the result and fill it in - jfieldID* result_list = (jfieldID*) jvmtiMalloc(result_count * sizeof(jfieldID)); - // The JVMTI spec requires fields in the order they occur in the class file, - // this is the reverse order of what FieldStream hands out. - int id_index = (result_count - 1); + int result_count = flds.field_count(); - for (FilteredFieldStream src_st(ik, true, true); !src_st.eos(); src_st.next()) { - result_list[id_index--] = jfieldIDWorkaround::to_jfieldID( - ik, src_st.offset(), - src_st.access_flags().is_static()); + // Allocate the result and fill it in. + jfieldID* result_list = (jfieldID*)jvmtiMalloc(result_count * sizeof(jfieldID)); + for (int i = 0; i < result_count; i++, flds.next()) { + result_list[i] = jfieldIDWorkaround::to_jfieldID(ik, flds.offset(), + flds.access_flags().is_static()); } - assert(id_index == -1, "just checking"); + assert(flds.done(), "just checking"); + // Fill in the results *field_count_ptr = result_count; *fields_ptr = result_list; diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 9d6296ee31603..6a3ee71870901 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/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 969e14f150e17..26c915852e589 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"); diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index dc5177942c450..4d5777059e008 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 2cfaba170540d..da774fe1620e4 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/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 2214713aa4bf6..a8e2e571c5bbd 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 ab48bd19b5e43..281067fe55c6b 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -353,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 0eb4015a24659..dad10a7b9b4d8 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 8ecabde8ca144..f93328f52700b 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -789,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); @@ -1062,6 +1063,7 @@ class os: AllStatic { char pathSep); static bool set_boot_path(char fileSep, char pathSep); + static bool pd_dll_unload(void* libhandle, char* ebuf, int ebuflen); }; // Note that "PAUSE" is almost always used with synchronization diff --git a/src/hotspot/share/runtime/reflectionUtils.hpp b/src/hotspot/share/runtime/reflectionUtils.hpp index 93bb541467aa5..5d43d27f66017 100644 --- a/src/hotspot/share/runtime/reflectionUtils.hpp +++ b/src/hotspot/share/runtime/reflectionUtils.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 @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_REFLECTIONUTILS_HPP #include "memory/allStatic.hpp" +#include "oops/fieldStreams.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oopsHierarchy.hpp" @@ -237,4 +238,36 @@ class FilteredFieldStream : public FieldStream { } }; +// Iterate over Java fields filtering fields like reflection does. +class FilteredJavaFieldStream : public JavaFieldStream { +private: + InstanceKlass* _klass; + int _filtered_fields_count; + bool has_filtered_field() const { return (_filtered_fields_count > 0); } + void skip_filtered_fields() { + if (has_filtered_field()) { + while (!done() && FilteredFieldsMap::is_filtered_field((Klass*)_klass, offset())) { + JavaFieldStream::next(); + } + } + } + +public: + FilteredJavaFieldStream(InstanceKlass* klass) + : JavaFieldStream(klass), + _klass(klass), + _filtered_fields_count(FilteredFieldsMap::filtered_fields_count(klass, true)) + { + // skip filtered fields at the beginning + skip_filtered_fields(); + } + int field_count() const { + return _klass->java_fields_count() - _filtered_fields_count; + } + void next() { + JavaFieldStream::next(); + skip_filtered_fields(); + } +}; + #endif // SHARE_RUNTIME_REFLECTIONUTILS_HPP diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 34eafb01c6d74..dac77d6e0ac74 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -519,16 +519,18 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) LockStack& lock_stack = current->lock_stack(); if (lock_stack.can_push()) { markWord mark = obj()->mark_acquire(); - if (mark.is_neutral()) { - assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); + while (mark.is_neutral()) { + // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. // Try to swing into 'fast-locked' state. - markWord locked_mark = mark.set_fast_locked(); - markWord old_mark = obj()->cas_set_mark(locked_mark, mark); + assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); + const markWord locked_mark = mark.set_fast_locked(); + const markWord old_mark = obj()->cas_set_mark(locked_mark, mark); if (old_mark == mark) { // Successfully fast-locked, push object to lock-stack and return. lock_stack.push(obj()); return; } + mark = old_mark; } } // All other paths fall-through to inflate-enter. @@ -578,23 +580,15 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) markWord mark = object->mark(); if (LockingMode == LM_LIGHTWEIGHT) { // Fast-locking does not use the 'lock' argument. - if (mark.is_fast_locked()) { - markWord unlocked_mark = mark.set_unlocked(); - markWord old_mark = object->cas_set_mark(unlocked_mark, mark); - if (old_mark != mark) { - // Another thread won the CAS, it must have inflated the monitor. - // It can only have installed an anonymously locked monitor at this point. - // Fetch that monitor, set owner correctly to this thread, and - // exit it (allowing waiting threads to enter). - assert(old_mark.has_monitor(), "must have monitor"); - ObjectMonitor* monitor = old_mark.monitor(); - assert(monitor->is_owner_anonymous(), "must be anonymous owner"); - monitor->set_owner_from_anonymous(current); - monitor->exit(current); + while (mark.is_fast_locked()) { + // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. + const markWord unlocked_mark = mark.set_unlocked(); + const markWord old_mark = object->cas_set_mark(unlocked_mark, mark); + if (old_mark == mark) { + current->lock_stack().remove(object); + return; } - LockStack& lock_stack = current->lock_stack(); - lock_stack.remove(object); - return; + mark = old_mark; } } else if (LockingMode == LM_LEGACY) { markWord dhw = lock->displaced_header(); @@ -908,13 +902,6 @@ static inline intptr_t get_next_hash(Thread* current, oop obj) { return value; } -// Can be called from non JavaThreads (e.g., VMThread) for FastHashCode -// calculations as part of JVM/TI tagging. -static bool is_lock_owned(Thread* thread, oop obj) { - assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled"); - return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false; -} - intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { while (true) { @@ -926,7 +913,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)"); guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); } - if (mark.is_neutral()) { // if this is a normal header + if (mark.is_neutral() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) { hash = mark.hash(); if (hash != 0) { // if it has a hash, just return it return hash; @@ -938,6 +925,10 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { if (test == mark) { // if the hash was installed, return it return hash; } + if (LockingMode == LM_LIGHTWEIGHT) { + // CAS failed, retry + continue; + } // Failed to install the hash. It could be that another thread // installed the hash just before our attempt or inflation has // occurred or... so we fall thru to inflate the monitor for @@ -969,13 +960,6 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { } // Fall thru so we only have one place that installs the hash in // the ObjectMonitor. - } else if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked() && is_lock_owned(current, obj)) { - // This is a fast-lock owned by the calling thread so use the - // markWord from the object. - hash = mark.hash(); - if (hash != 0) { // if it has a hash, just return it - return hash; - } } else if (LockingMode == LM_LEGACY && mark.has_locker() && current->is_lock_owned((address)mark.locker())) { // This is a stack-lock owned by the calling thread so fetch the // displaced markWord from the BasicLock on the stack. @@ -1305,6 +1289,13 @@ void ObjectSynchronizer::inflate_helper(oop obj) { (void)inflate(Thread::current(), obj, inflate_cause_vm_internal); } +// Can be called from non JavaThreads (e.g., VMThread) for FastHashCode +// calculations as part of JVM/TI tagging. +static bool is_lock_owned(Thread* thread, oop obj) { + assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled"); + return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false; +} + ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop object, const InflateCause cause) { EventJavaMonitorInflate event; diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 851e5139f8aad..7401629bf943a 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -73,6 +73,7 @@ Thread::Thread() { set_lgrp_id(-1); DEBUG_ONLY(clear_suspendible_thread();) DEBUG_ONLY(clear_indirectly_suspendible_thread();) + DEBUG_ONLY(clear_indirectly_safepoint_thread();) // allocated data structures set_osthread(nullptr); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index cc431e8c90022..7461876f37846 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -207,6 +207,7 @@ class Thread: public ThreadShadow { private: DEBUG_ONLY(bool _suspendible_thread;) DEBUG_ONLY(bool _indirectly_suspendible_thread;) + DEBUG_ONLY(bool _indirectly_safepoint_thread;) public: // Determines if a heap allocation failure will be retried @@ -225,6 +226,10 @@ class Thread: public ThreadShadow { void set_indirectly_suspendible_thread() { _indirectly_suspendible_thread = true; } void clear_indirectly_suspendible_thread() { _indirectly_suspendible_thread = false; } bool is_indirectly_suspendible_thread() { return _indirectly_suspendible_thread; } + + void set_indirectly_safepoint_thread() { _indirectly_safepoint_thread = true; } + void clear_indirectly_safepoint_thread() { _indirectly_safepoint_thread = false; } + bool is_indirectly_safepoint_thread() { return _indirectly_safepoint_thread; } #endif private: diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index a46101f6d8d1d..add86b338deef 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1641,6 +1641,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 @@ -1918,7 +1931,10 @@ 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 (java_lang_VirtualThread::is_instance(o) && ThreadDumper::should_dump_vthread(o)) { + // 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()) { diff --git a/src/hotspot/share/utilities/events.cpp b/src/hotspot/share/utilities/events.cpp index dd64c72dd8a04..f89821800d14d 100644 --- a/src/hotspot/share/utilities/events.cpp +++ b/src/hotspot/share/utilities/events.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/shared/gc_globals.hpp" #include "memory/allocation.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/symbol.hpp" @@ -97,7 +98,9 @@ void Events::init() { if (LogEvents) { _messages = new StringEventLog("Events", "events"); _vm_operations = new StringEventLog("VM Operations", "vmops"); - _zgc_phase_switch = new StringEventLog("ZGC Phase Switch", "zgcps"); + if (UseZGC) { + _zgc_phase_switch = new StringEventLog("ZGC Phase Switch", "zgcps"); + } _exceptions = new ExceptionsEventLog("Internal exceptions", "exc"); _redefinitions = new StringEventLog("Classes redefined", "redef"); _class_unloading = new UnloadingEventLog("Classes unloaded", "unload"); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index d586c6f4eeacf..d40504d6d2008 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/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c index 14094e11c45df..99dbbcb41d708 100644 --- a/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, 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 @@ -427,6 +427,9 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarInt (JNIEnv *env, jclass cls, jstring jlangtag, jint type) { jint ret = 0; + // Majority of MacOSX fixed locales return Gregorian cal identifier + // Using CFCalendarCopyCurrent() provides a cal that is based off OS settings + // which is more accurate than one created with a Gregorian identifier CFCalendarRef cfcal = CFCalendarCopyCurrent(); if (cfcal != NULL) { diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 851d65d06ad77..4573a6dc69004 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 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 @@ -261,7 +261,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 @@ -314,6 +315,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('@'); } @@ -344,6 +350,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/System.java b/src/java.base/share/classes/java/lang/System.java index 0c10079316722..39ecb2a6436ca 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 @@ -57,6 +57,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; @@ -813,6 +814,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 @@ -2374,7 +2379,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 4236368d28743..c3a6a3de5bc0f 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; } } @@ -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 diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 6f82516d86452..72ae1070242e8 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 @@ -852,18 +852,32 @@ 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(); + + // 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; - Interruptible b = nioBlocker; - if (b != null) { - b.interrupt(this); + blocker = nioBlocker(); + if (blocker != null) { + blocker.interrupt(this); } // interrupt carrier thread if mounted @@ -873,6 +887,11 @@ public void interrupt() { } finally { notifyJvmtiDisableSuspend(false); } + + // notify blocker after releasing interruptLock + if (blocker != null) { + blocker.postInterrupt(); + } } else { interrupted = true; carrierThread.setInterrupt(); diff --git a/src/java.base/share/classes/java/lang/foreign/Arena.java b/src/java.base/share/classes/java/lang/foreign/Arena.java index 195f8a44db6e3..7618fa727a47b 100644 --- a/src/java.base/share/classes/java/lang/foreign/Arena.java +++ b/src/java.base/share/classes/java/lang/foreign/Arena.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 @@ -219,6 +219,9 @@ public interface Arena extends SegmentAllocator, AutoCloseable { * Segments allocated with the returned arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. + *

    + * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. * * @return a new arena that is managed, automatically, by the garbage collector */ @@ -231,6 +234,9 @@ static Arena ofAuto() { * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in * an {@link UnsupportedOperationException}. + *

    + * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena global() { class Holder { @@ -243,6 +249,9 @@ class Holder { * {@return a new confined arena} Segments allocated with the confined arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread * that created the arena, the arena's owner thread. + *

    + * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena ofConfined() { return MemorySessionImpl.createConfined(Thread.currentThread()).asArena(); @@ -251,6 +260,9 @@ static Arena ofConfined() { /** * {@return a new shared arena} Segments allocated with the global arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. + *

    + * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena ofShared() { return MemorySessionImpl.createShared().asArena(); diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 321d9b09bad34..8a2b3b4df303e 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -1016,7 +1016,7 @@ static PaddingLayout paddingLayout(long byteSize) { * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0} */ static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { - MemoryLayoutUtil.requireNonNegative(elementCount); + Utils.checkNonNegativeArgument(elementCount, "elementCount"); Objects.requireNonNull(elementLayout); Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment"); diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index da255b9912b25..faf28b01bf0ac 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -44,6 +44,7 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.MemorySessionImpl; import jdk.internal.foreign.SegmentFactories; +import jdk.internal.foreign.Utils; import jdk.internal.javac.Restricted; import jdk.internal.reflect.CallerSensitive; import jdk.internal.vm.annotation.ForceInline; @@ -1591,6 +1592,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ byte get(ValueLayout.OfByte layout, long offset); @@ -1609,6 +1611,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1629,6 +1632,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ boolean get(ValueLayout.OfBoolean layout, long offset); @@ -1647,6 +1651,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1667,6 +1672,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ char get(ValueLayout.OfChar layout, long offset); @@ -1685,6 +1691,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1705,6 +1712,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ short get(ValueLayout.OfShort layout, long offset); @@ -1723,6 +1731,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1743,6 +1752,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ int get(ValueLayout.OfInt layout, long offset); @@ -1761,6 +1771,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1781,6 +1792,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ float get(ValueLayout.OfFloat layout, long offset); @@ -1799,6 +1811,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1819,6 +1832,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ long get(ValueLayout.OfLong layout, long offset); @@ -1837,6 +1851,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1857,6 +1872,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ double get(ValueLayout.OfDouble layout, long offset); @@ -1875,6 +1891,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1905,6 +1922,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in {@code T} * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ MemorySegment get(AddressLayout layout, long offset); @@ -1923,8 +1941,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is - * {@linkplain #isReadOnly() read-only} + * or {@code offset < 0} * @throws IllegalArgumentException if {@code value} is not a * {@linkplain #isNative() native} segment * @throws IllegalArgumentException if this segment is @@ -1951,6 +1968,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ byte getAtIndex(ValueLayout.OfByte layout, long index); @@ -1973,6 +1991,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ boolean getAtIndex(ValueLayout.OfBoolean layout, long index); @@ -1995,6 +2014,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ char getAtIndex(ValueLayout.OfChar layout, long index); @@ -2017,7 +2037,8 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * or {@code index < 0} + * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfChar layout, long index, char value); @@ -2040,6 +2061,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ short getAtIndex(ValueLayout.OfShort layout, long index); @@ -2061,6 +2083,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfByte layout, long index, byte value); @@ -2084,6 +2107,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value); @@ -2107,6 +2131,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfShort layout, long index, short value); @@ -2130,6 +2155,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ int getAtIndex(ValueLayout.OfInt layout, long index); @@ -2152,6 +2178,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfInt layout, long index, int value); @@ -2175,6 +2202,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ float getAtIndex(ValueLayout.OfFloat layout, long index); @@ -2197,6 +2225,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfFloat layout, long index, float value); @@ -2220,6 +2249,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ long getAtIndex(ValueLayout.OfLong layout, long index); @@ -2242,6 +2272,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfLong layout, long index, long value); @@ -2265,6 +2296,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ double getAtIndex(ValueLayout.OfDouble layout, long index); @@ -2287,6 +2319,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfDouble layout, long index, double value); @@ -2319,6 +2352,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * in {@code T} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ MemorySegment getAtIndex(AddressLayout layout, long index); @@ -2341,7 +2375,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * or {@code index < 0} * @throws IllegalArgumentException if {@code value} is not a {@linkplain #isNative() native} segment * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 6be9d949ea652..6c9cf51bee8b7 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -33,6 +33,7 @@ import jdk.internal.foreign.ArenaImpl; import jdk.internal.foreign.SlicingAllocator; import jdk.internal.foreign.StringSupport; +import jdk.internal.foreign.Utils; import jdk.internal.vm.annotation.ForceInline; /** @@ -390,9 +391,10 @@ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { * with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code source.isAccessibleBy(T) == false} - * @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows + * @throws IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows + * @throws IllegalArgumentException if {@code elementCount < 0} * @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} - * @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0} + * @throws IndexOutOfBoundsException if {@code sourceOffset < 0} */ @ForceInline default MemorySegment allocateFrom(ValueLayout elementLayout, diff --git a/src/java.base/share/classes/java/lang/reflect/Modifier.java b/src/java.base/share/classes/java/lang/reflect/Modifier.java index e0f60d5851104..4b13d19f85eaf 100644 --- a/src/java.base/share/classes/java/lang/reflect/Modifier.java +++ b/src/java.base/share/classes/java/lang/reflect/Modifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,15 @@ * {@jvms 4.1}, {@jvms 4.4}, {@jvms 4.5}, and {@jvms 4.7} of * The Java Virtual Machine Specification. * + * @apiNote + * Not all modifiers that are syntactic Java language modifiers are + * represented in this class, only those modifiers that also + * have a corresponding JVM {@linkplain AccessFlag access flag} are + * included. In particular the {@code default} method modifier (JLS + * {@jls 9.4.3}) and the {@code sealed} and {@code non-sealed} class + * (JLS {@jls 8.1.1.2}) and interface (JLS {@jls 9.1.1.4}) modifiers + * are not represented in this class. + * * @see Class#getModifiers() * @see Member#getModifiers() * @@ -208,6 +217,7 @@ public static boolean isStrict(int mod) { * public protected private abstract static final transient * volatile synchronized native strictfp * interface } + * * The {@code interface} modifier discussed in this class is * not a true modifier in the Java language and it appears after * all other modifiers listed by this method. This method may @@ -221,6 +231,22 @@ public static boolean isStrict(int mod) { * {@code toString} with the appropriate mask from a method like * {@link #constructorModifiers} or {@link #methodModifiers}. * + * @apiNote + * To make a high-fidelity representation of the Java source + * modifiers of a class or member, source-level modifiers that do + * not have a constant in this class should be included + * and appear in an order consistent with the full recommended + * ordering for that kind of declaration as given in The + * Java Language Specification. For example, for a + * {@linkplain Method#toGenericString() method} the "{@link + * Method#isDefault() default}" modifier is ordered immediately + * before "{@code static}" (JLS {@jls 9.4}). For a {@linkplain + * Class#toGenericString() class object}, the "{@link + * Class#isSealed() sealed}" or {@code "non-sealed"} modifier is + * ordered immediately after "{@code final}" for a class (JLS + * {@jls 8.1.1}) and immediately after "{@code static}" for an + * interface (JLS {@jls 9.1.1}). + * * @param mod a set of modifiers * @return a string representation of the set of modifiers * represented by {@code mod} diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 98f55ef3c8c0f..8d12c6de0a7e3 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -45,6 +45,7 @@ import jdk.internal.math.DoubleConsts; import jdk.internal.math.FloatConsts; +import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -3963,6 +3964,7 @@ public boolean isProbablePrime(int certainty) { * @return -1, 0 or 1 as this BigInteger is numerically less than, equal * to, or greater than {@code val}. */ + @Override public int compareTo(BigInteger val) { if (signum == val.signum) { return switch (signum) { @@ -3991,12 +3993,9 @@ final int compareMagnitude(BigInteger val) { return -1; if (len1 > len2) return 1; - for (int i = 0; i < len1; i++) { - int a = m1[i]; - int b = m2[i]; - if (a != b) - return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; - } + int i = ArraysSupport.mismatch(m1, m2, len1); + if (i != -1) + return Integer.compareUnsigned(m1[i], m2[i]) < 0 ? -1 : 1; return 0; } @@ -4023,7 +4022,7 @@ final int compareMagnitude(long val) { int a = m1[0]; int b = (int)val; if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; + return Integer.compareUnsigned(a, b) < 0 ? -1 : 1; } return 0; } else { @@ -4032,12 +4031,12 @@ final int compareMagnitude(long val) { int a = m1[0]; int b = highWord; if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; + return Integer.compareUnsigned(a, b) < 0 ? -1 : 1; } a = m1[1]; b = (int)val; if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; + return Integer.compareUnsigned(a, b) < 0 ? -1 : 1; } return 0; } @@ -4050,6 +4049,7 @@ final int compareMagnitude(long val) { * @return {@code true} if and only if the specified Object is a * BigInteger whose value is numerically equal to this BigInteger. */ + @Override public boolean equals(Object x) { // This test is just an optimization, which may or may not help if (x == this) @@ -4061,17 +4061,10 @@ public boolean equals(Object x) { if (xInt.signum != signum) return false; - int[] m = mag; - int len = m.length; - int[] xm = xInt.mag; - if (len != xm.length) + if (mag.length != xInt.mag.length) return false; - for (int i = 0; i < len; i++) - if (xm[i] != m[i]) - return false; - - return true; + return ArraysSupport.mismatch(mag, xInt.mag, mag.length) == -1; } /** @@ -4100,17 +4093,12 @@ public BigInteger max(BigInteger val) { // Hash Function /** - * Returns the hash code for this BigInteger. - * - * @return hash code for this BigInteger. + * {@return the hash code for this BigInteger} */ + @Override public int hashCode() { - int hashCode = 0; - - for (int i=0; i < mag.length; i++) - hashCode = (int)(31*hashCode + (mag[i] & LONG_MASK)); - - return hashCode * signum; + return ArraysSupport.vectorizedHashCode(mag, 0, mag.length, 0, + ArraysSupport.T_INT) * signum; } /** diff --git a/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java b/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java index 26dfc5ebca5e1..6adf2eb227634 100644 --- a/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java +++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java @@ -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 @@ -32,9 +32,9 @@ import java.nio.channels.InterruptibleChannel; import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Unsafe; import sun.nio.ch.Interruptible; - /** * Base implementation class for interruptible channels. * @@ -89,10 +89,26 @@ public abstract class AbstractInterruptibleChannel private final Object closeLock = new Object(); private volatile boolean closed; + // invoked if a Thread is interrupted when blocked in an I/O op + private final Interruptible interruptor; + /** * Initializes a new instance of this class. */ - protected AbstractInterruptibleChannel() { } + protected AbstractInterruptibleChannel() { + this.interruptor = new Interruptible() { + @Override + public void interrupt(Thread target) { + AbstractInterruptibleChannel.this.trySetTarget(target); + } + @Override + public void postInterrupt() { + try { + AbstractInterruptibleChannel.this.close(); + } catch (IOException x) { } + } + }; + } /** * Closes this channel. @@ -139,8 +155,15 @@ public final boolean isOpen() { // -- Interruption machinery -- - private Interruptible interruptor; - private volatile Thread interrupted; + private static final Unsafe U = Unsafe.getUnsafe(); + private static final long INTERRUPTED_TARGET = + U.objectFieldOffset(AbstractInterruptibleChannel.class, "interruptedTarget"); + private volatile Object interruptedTarget; // Thread or placeholder object + + private void trySetTarget(Thread target) { + // can't use VarHandle here as CAS may park on first usage + U.compareAndSetReference(this, INTERRUPTED_TARGET, null, target); + } /** * Marks the beginning of an I/O operation that might block indefinitely. @@ -151,24 +174,12 @@ public final boolean isOpen() { * closing and interruption for this channel.

    */ protected final void begin() { - if (interruptor == null) { - interruptor = new Interruptible() { - public void interrupt(Thread target) { - synchronized (closeLock) { - if (closed) - return; - closed = true; - interrupted = target; - try { - AbstractInterruptibleChannel.this.implCloseChannel(); - } catch (IOException x) { } - } - }}; - } blockedOn(interruptor); Thread me = Thread.currentThread(); - if (me.isInterrupted()) + if (me.isInterrupted()) { interruptor.interrupt(me); + interruptor.postInterrupt(); + } } /** @@ -194,10 +205,14 @@ protected final void end(boolean completed) throws AsynchronousCloseException { blockedOn(null); - Thread interrupted = this.interrupted; - if (interrupted != null && interrupted == Thread.currentThread()) { - this.interrupted = null; - throw new ClosedByInterruptException(); + Object interruptedTarget = this.interruptedTarget; + if (interruptedTarget != null) { + interruptor.postInterrupt(); + if (interruptedTarget == Thread.currentThread()) { + // replace with dummy object to avoid retaining reference to this thread + this.interruptedTarget = new Object(); + throw new ClosedByInterruptException(); + } } if (!completed && closed) throw new AsynchronousCloseException(); diff --git a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java index d04485471cc68..7ea5f89221834 100644 --- a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java +++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java @@ -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 @@ -89,6 +89,9 @@ public abstract class AbstractSelector // cancelled-key, not used by the JDK Selector implementations private final Set cancelledKeys; + // invoked if a Thread is interrupted when blocked on a selection op + private final Interruptible interruptor; + /** * Initializes a new instance of this class. * @@ -103,6 +106,15 @@ protected AbstractSelector(SelectorProvider provider) { } else { this.cancelledKeys = new HashSet<>(); } + this.interruptor = new Interruptible() { + @Override + public void interrupt(Thread ignore) { + } + @Override + public void postInterrupt() { + AbstractSelector.this.wakeup(); + } + }; } void cancel(SelectionKey k) { // package-private @@ -209,8 +221,6 @@ protected final void deregister(AbstractSelectionKey key) { // -- Interruption machinery -- - private Interruptible interruptor = null; - /** * Marks the beginning of an I/O operation that might block indefinitely. * @@ -225,16 +235,11 @@ protected final void deregister(AbstractSelectionKey key) { * blocked in an I/O operation upon the selector.

    */ protected final void begin() { - if (interruptor == null) { - interruptor = new Interruptible() { - public void interrupt(Thread ignore) { - AbstractSelector.this.wakeup(); - }}; - } AbstractInterruptibleChannel.blockedOn(interruptor); Thread me = Thread.currentThread(); - if (me.isInterrupted()) - interruptor.interrupt(me); + if (me.isInterrupted()) { + interruptor.postInterrupt(); + } } /** @@ -248,5 +253,4 @@ public void interrupt(Thread ignore) { protected final void end() { AbstractInterruptibleChannel.blockedOn(null); } - } diff --git a/src/java.base/share/classes/java/nio/file/FileStore.java b/src/java.base/share/classes/java/nio/file/FileStore.java index fc191d69c1c53..cdd8f66f45a8b 100644 --- a/src/java.base/share/classes/java/nio/file/FileStore.java +++ b/src/java.base/share/classes/java/nio/file/FileStore.java @@ -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 @@ -103,11 +103,11 @@ protected FileStore() { *

    The returned number of available bytes is a hint, but not a * guarantee, that it is possible to use most or any of these bytes. The * number of usable bytes is most likely to be accurate immediately - * after the space attributes are obtained. It is likely to be made inaccurate + * after this method returns. It is likely to be made inaccurate * by any external I/O operations including those made on the system outside * of this Java virtual machine. * - * @return the number of bytes available + * @return the current number of usable bytes * * @throws IOException * if an I/O error occurs @@ -122,11 +122,11 @@ protected FileStore() { *

    The returned number of unallocated bytes is a hint, but not a * guarantee, that it is possible to use most or any of these bytes. The * number of unallocated bytes is most likely to be accurate immediately - * after the space attributes are obtained. It is likely to be + * after this method returns. It is likely to be * made inaccurate by any external I/O operations including those made on * the system outside of this virtual machine. * - * @return the number of unallocated bytes + * @return the current number of unallocated bytes * * @throws IOException * if an I/O error occurs diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 02f556489e641..88a49a94f9be5 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -45,6 +45,7 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; +import java.text.DateFormat; import java.text.MessageFormat; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.LocaleNameProvider; @@ -258,6 +259,74 @@ * locales. For example, {@code Locale.US} is the {@code Locale} object * for the United States. * + *

    Default Locale

    + * + *

    The default Locale is provided for any locale-sensitive methods if no + * {@code Locale} is explicitly specified as an argument, such as + * {@link DateFormat#getInstance()}. The default Locale is determined at startup + * of the Java runtime and established in the following three phases: + *

      + *
    1. The locale-related system properties listed below are established from the + * host environment. Some system properties (except for {@code user.language}) may + * not have values from the host environment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      Shows property keys and associated values
      Locale-related System Properties KeyDescription
      {@systemProperty user.language}{@link ##def_language language} for the default Locale, + * such as "en" (English)
      {@systemProperty user.script}{@link ##def_script script} for the default Locale, + * such as "Latn" (Latin)
      {@systemProperty user.country}{@link ##def_region country} for the default Locale, + * such as "US" (United States)
      {@systemProperty user.variant}{@link ##def_variant variant} for the default Locale, + * such as "POSIX"
      {@systemProperty user.extensions}{@link ##def_extensions extensions} for the default Locale, + * such as "u-ca-japanese" (Japanese Calendar)
      + *
    2. + *
    3. The values of these system properties can be overridden by values designated + * at startup time. If the overriding value of the {@code user.extensions} property + * is unparsable, it is ignored. The overriding values of other properties are not + * checked for syntax or validity and are used directly in the default Locale. + * (Typically, system property values can be provided using the {@code -D} command-line + * option of a launcher. For example, specifying {@code -Duser.extensions=foobarbaz} + * results in a default Locale with no extensions, while specifying + * {@code -Duser.language=foobarbaz} results in a default Locale whose language is + * "foobarbaz".) + *
    4. + *
    5. The default {@code Locale} instance is constructed from the values of these + * system properties. + *
    6. + *
    + *

    Altering the system property values with {@link System#setProperties(Properties)}/ + * {@link System#setProperty(String, String)} has no effect on the default Locale. + *

    Once the default Locale is established, applications can query the default + * Locale with {@link #getDefault()} and change it with {@link #setDefault(Locale)}. + * If the default Locale is changed with {@link #setDefault(Locale)}, the corresponding + * system properties are not altered. It is not recommended that applications read + * these system properties and parse or interpret them as their values may be out of date. + * + *

    There are finer-grained default Locales specific for each {@link Locale.Category}. + * These category specific default Locales can be queried by {@link #getDefault(Category)}, + * and set by {@link #setDefault(Category, Locale)}. Construction of these category + * specific default Locales are determined by the corresponding system properties, + * which consist of the base system properties as listed above, suffixed by either + * {@code ".display"} or {@code ".format"} depending on the category. For example, + * the value of the {@code user.language.display} system property will be used in the + * {@code language} part of the default Locale for the {@link Locale.Category#DISPLAY} + * category. In the absence of category specific system properties, the "category-less" + * system properties are used, such as {@code user.language} in the previous example. + * *

    Locale Matching

    * *

    If an application or a system is internationalized and provides localized @@ -984,14 +1053,14 @@ public int hashCode() { } /** - * Gets the current value of the default locale for this instance - * of the Java Virtual Machine. + * Gets the current value of the {@link ##default_locale default locale} for + * this instance of the Java Virtual Machine. *

    * The Java Virtual Machine sets the default locale during startup * based on the host environment. It is used by many locale-sensitive * methods if no locale is explicitly specified. * It can be changed using the - * {@link #setDefault(java.util.Locale) setDefault} method. + * {@link #setDefault(Locale)} method. * * @return the default locale for this instance of the Java Virtual Machine */ @@ -1001,13 +1070,13 @@ public static Locale getDefault() { } /** - * Gets the current value of the default locale for the specified Category - * for this instance of the Java Virtual Machine. + * Gets the current value of the {@link ##default_locale default locale} for + * the specified Category for this instance of the Java Virtual Machine. *

    * The Java Virtual Machine sets the default locale during startup based * on the host environment. It is used by many locale-sensitive methods * if no locale is explicitly specified. It can be changed using the - * setDefault(Locale.Category, Locale) method. + * {@link #setDefault(Locale.Category, Locale)} method. * * @param category the specified category to get the default locale * @throws NullPointerException if category is null @@ -1108,8 +1177,9 @@ private static Optional getDefaultExtensions(String extensions } /** - * Sets the default locale for this instance of the Java Virtual Machine. - * This does not affect the host locale. + * Sets the {@link ##default_locale default locale} for + * this instance of the Java Virtual Machine. This does not affect the + * host locale. *

    * If there is a security manager, its {@code checkPermission} * method is called with a {@code PropertyPermission("user.language", "write")} @@ -1142,8 +1212,9 @@ public static synchronized void setDefault(Locale newLocale) { } /** - * Sets the default locale for the specified Category for this instance - * of the Java Virtual Machine. This does not affect the host locale. + * Sets the {@link ##default_locale default locale} for the specified + * Category for this instance of the Java Virtual Machine. This does + * not affect the host locale. *

    * If there is a security manager, its checkPermission method is called * with a PropertyPermission("user.language", "write") permission before diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 5aef5cd12a155..a0d3176c76251 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -1143,7 +1143,8 @@ public LinkedTransferQueue(Collection c) { * @throws NullPointerException if the specified element is null */ public void put(E e) { - offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); } /** @@ -1156,7 +1157,9 @@ public void put(E e) { * @throws NullPointerException if the specified element is null */ public boolean offer(E e, long timeout, TimeUnit unit) { - return offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); + return true; } /** @@ -1181,7 +1184,9 @@ public boolean offer(E e) { * @throws NullPointerException if the specified element is null */ public boolean add(E e) { - return offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); + return true; } /** diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index e05027a7abcfc..7df7fa236c806 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.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,6 +29,7 @@ import java.security.*; import java.security.InvalidAlgorithmParameterException; import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -539,10 +540,19 @@ public static KEM getInstance(String algorithm) List list = GetInstance.getServices( "KEM", Objects.requireNonNull(algorithm, "null algorithm name")); - if (list.isEmpty()) { - throw new NoSuchAlgorithmException(algorithm + " KEM not available"); + List allowed = new ArrayList<>(); + for (Provider.Service s : list) { + if (!JceSecurity.canUseProvider(s.getProvider())) { + continue; + } + allowed.add(s); + } + if (allowed.isEmpty()) { + throw new NoSuchAlgorithmException + (algorithm + " KEM not available"); } - return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0]))); + + return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0]))); } /** @@ -568,7 +578,7 @@ public static KEM getInstance(String algorithm, Provider provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), @@ -601,7 +611,7 @@ public static KEM getInstance(String algorithm, String provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 305594952d44e..0efe62c1e4fbc 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -153,9 +153,7 @@ public final MemorySegment reinterpret(Arena arena, Consumer clea public MemorySegment reinterpretInternal(Class callerClass, long newSize, Scope scope, Consumer cleanup) { Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret"); - if (newSize < 0) { - throw new IllegalArgumentException("newSize < 0"); - } + Utils.checkNonNegativeArgument(newSize, "newSize"); if (!isNative()) throw new UnsupportedOperationException("Not a native segment"); Runnable action = cleanup != null ? () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) : @@ -594,6 +592,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, long elementCount) { + Utils.checkNonNegativeIndex(elementCount, "elementCount"); AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment; if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) { @@ -625,7 +624,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset, Object dstArray, int dstIndex, int elementCount) { - + Utils.checkNonNegativeIndex(elementCount, "elementCount"); var dstInfo = Utils.BaseAndScale.of(dstArray); if (dstArray.getClass().componentType() != srcLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + srcLayout); @@ -652,7 +651,6 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long sr public static void copy(Object srcArray, int srcIndex, MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset, int elementCount) { - var srcInfo = Utils.BaseAndScale.of(srcArray); if (srcArray.getClass().componentType() != dstLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + dstLayout); diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index d0d5c866f6b4e..6a081e23eac0d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -200,11 +200,8 @@ public static long pointeeByteAlign(AddressLayout addressLayout) { } public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) { - // size should be >= 0 - if (byteSize < 0) { - throw new IllegalArgumentException("Invalid allocation size : " + byteSize); - } - + // byteSize should be >= 0 + Utils.checkNonNegativeArgument(byteSize, "allocation size"); checkAlign(byteAlignment); } @@ -216,6 +213,20 @@ public static void checkAlign(long byteAlignment) { } } + @ForceInline + public static void checkNonNegativeArgument(long value, String name) { + if (value < 0) { + throw new IllegalArgumentException("The provided " + name + " is negative: " + value); + } + } + + @ForceInline + public static void checkNonNegativeIndex(long value, String name) { + if (value < 0) { + throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value); + } + } + private static long computePadding(long offset, long align) { boolean isAligned = offset == 0 || offset % align == 0; if (isAligned) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java index e4d931127af99..3c0cf3902bbd0 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java @@ -151,13 +151,8 @@ private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) { } public long scale(long offset, long index) { - if (offset < 0) { - throw new IllegalArgumentException("Negative offset: " + offset); - } - if (index < 0) { - throw new IllegalArgumentException("Negative index: " + index); - } - + Utils.checkNonNegativeArgument(offset, "offset"); + Utils.checkNonNegativeArgument(index, "index"); return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java index dce061410285f..6b8e7738198cc 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java @@ -30,13 +30,6 @@ public final class MemoryLayoutUtil { private MemoryLayoutUtil() { } - public static long requireNonNegative(long value) { - if (value < 0) { - throw new IllegalArgumentException("The provided value was negative: " + value); - } - return value; - } - public static long requireByteSizeValid(long byteSize, boolean allowZero) { if ((byteSize == 0 && !allowZero) || byteSize < 0) { throw new IllegalArgumentException("Invalid byte size: " + byteSize); diff --git a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java index 7f8f3fcc8ec1d..4f93ce9473176 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java +++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, 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 @@ -25,6 +25,7 @@ package jdk.internal.jimage.decompressor; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.zip.Inflater; /** @@ -44,29 +45,33 @@ public String getName() { return ZipDecompressorFactory.NAME; } - static byte[] decompress(byte[] bytesIn, int offset) throws Exception { + static byte[] decompress(byte[] bytesIn, int offset, long originalSize) throws Exception { + if (originalSize > Integer.MAX_VALUE) { + throw new OutOfMemoryError("Required array size too large"); + } + byte[] bytesOut = new byte[(int) originalSize]; + Inflater inflater = new Inflater(); inflater.setInput(bytesIn, offset, bytesIn.length - offset); - ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length - offset); - byte[] buffer = new byte[1024]; - while (!inflater.finished()) { - int count = inflater.inflate(buffer); - stream.write(buffer, 0, count); + int count = 0; + while (!inflater.finished() && count < originalSize) { + count += inflater.inflate(bytesOut, count, bytesOut.length - count); } - stream.close(); - - byte[] bytesOut = stream.toByteArray(); inflater.end(); + if (count != originalSize) { + throw new IOException("Resource content size mismatch"); + } + return bytesOut; } @Override public byte[] decompress(StringsProvider reader, byte[] content, int offset, long originalSize) throws Exception { - byte[] decompressed = decompress(content, offset); + byte[] decompressed = decompress(content, offset, originalSize); return decompressed; } } diff --git a/src/java.base/share/classes/sun/nio/ch/Interruptible.java b/src/java.base/share/classes/sun/nio/ch/Interruptible.java index 8445e35f05095..5785ba52e24d6 100644 --- a/src/java.base/share/classes/sun/nio/ch/Interruptible.java +++ b/src/java.base/share/classes/sun/nio/ch/Interruptible.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, 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 @@ -31,6 +31,23 @@ public interface Interruptible { - public void interrupt(Thread t); + /** + * Invoked by Thread.interrupt when the given Thread is interrupted. Thread.interrupt + * invokes this method while holding the given Thread's interrupt lock. This method + * is also invoked by AbstractInterruptibleChannel when beginning an I/O operation + * with the current thread's interrupt status set. This method must not block. + */ + void interrupt(Thread target); + + /** + * Invoked by Thread.interrupt after releasing the Thread's interrupt lock. + * It may also be invoked by AbstractInterruptibleChannel or AbstractSelector when + * beginning an I/O operation with the current thread's interrupt status set, or at + * the end of an I/O operation when any thread doing I/O on the channel (or selector) + * has been interrupted. This method closes the channel (or wakes up the Selector) to + * ensure that AsynchronousCloseException or ClosedByInterruptException is thrown. + * This method is required to be idempotent. + */ + void postInterrupt(); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java index 52572643511e0..d64ac90e9ac7f 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java @@ -386,7 +386,9 @@ LateBoundInputMap getTableInputMap() { "shift ENTER", "selectPreviousRowCell", "alt TAB", "focusHeader", "alt shift TAB", "focusHeader", - "F8", "focusHeader" + "F8", "focusHeader", + "ctrl shift UP", "selectFirstRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection" })); } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m index 33b986a0d180e..77d1e216a75c2 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m @@ -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 @@ -1697,6 +1697,7 @@ + (AWTWindow *) lastKeyWindow { int shieldLevel = CGShieldingWindowLevel(); window.preFullScreenLevel = [nsWindow level]; [nsWindow setLevel: shieldLevel]; + [nsWindow makeKeyAndOrderFront: nil]; NSRect screenRect = [[nsWindow screen] frame]; [nsWindow setFrame:screenRect display:YES]; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 3ae303660a354..72b8c759e30b5 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -1058,7 +1058,7 @@ public Object createValue(UIDefaults table) { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -1066,7 +1066,7 @@ public Object createValue(UIDefaults table) { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java index 120d59fbcbba1..be3b8cc60ee83 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java @@ -1029,7 +1029,7 @@ public Object createValue(UIDefaults table) { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -1037,7 +1037,7 @@ public Object createValue(UIDefaults table) { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/classes/javax/swing/ImageIcon.java b/src/java.desktop/share/classes/javax/swing/ImageIcon.java index be7179e6201c0..2eeac8961bcfe 100644 --- a/src/java.desktop/share/classes/javax/swing/ImageIcon.java +++ b/src/java.desktop/share/classes/javax/swing/ImageIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, 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 @@ -330,6 +330,7 @@ protected void loadImage(Image image) { mTracker.waitForID(id, 0); } catch (InterruptedException e) { interrupted = true; + Thread.currentThread().interrupt(); } loadStatus = mTracker.statusID(id, false); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 0f7857e992b63..999e7f923c744 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1461,7 +1461,7 @@ public Object createValue(UIDefaults table) { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -1469,7 +1469,7 @@ public Object createValue(UIDefaults table) { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java index 29bd0acdcc71c..98747bbd2dc95 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -1187,7 +1187,7 @@ protected void initComponentDefaults(UIDefaults table) { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -1195,7 +1195,7 @@ protected void initComponentDefaults(UIDefaults table) { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java index f25b25166bc51..1808aeeb75f93 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthStyle.java @@ -573,7 +573,7 @@ private static void populateDefaultValues() { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -581,7 +581,7 @@ private static void populateDefaultValues() { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java index ce9ae2813e843..f9d0d6eb1fad1 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java @@ -73,7 +73,9 @@ public class SynthTreeUI extends BasicTreeUI private boolean useTreeColors; - private Icon expandedIconWrapper = new ExpandedIconWrapper(); + private Icon expandedIconWrapper; + + private Icon collapsedIconWrapper; /** * @@ -99,12 +101,19 @@ public Icon getExpandedIcon() { return expandedIconWrapper; } + @Override + public Icon getCollapsedIcon() { + return collapsedIconWrapper; + } + /** * {@inheritDoc} */ @Override protected void installDefaults() { updateStyle(tree); + expandedIconWrapper = new IconWrapper(expandedIcon); + collapsedIconWrapper = new IconWrapper(collapsedIcon); } private void updateStyle(JTree tree) { @@ -778,44 +787,40 @@ public String getName() { } // - // BasicTreeUI directly uses expandIcon outside of the Synth methods. + // BasicTreeUI directly uses expandIcon and collapsedIcon outside of the + // Synth methods. // To get the correct context we return an instance of this that fetches // the SynthContext as needed. // - private class ExpandedIconWrapper implements SynthIcon { + + private class IconWrapper implements SynthIcon { + Icon iconType; + + public IconWrapper(Icon type) { + super(); + iconType = type; + } + public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { if (context == null) { context = getContext(tree); - SynthGraphicsUtils.paintIcon(expandedIcon, context, g, x, y, w, h); - } - else { - SynthGraphicsUtils.paintIcon(expandedIcon, context, g, x, y, w, h); } + SynthGraphicsUtils.paintIcon(iconType, context, g, x, y, w, h); } public int getIconWidth(SynthContext context) { - int width; if (context == null) { context = getContext(tree); - width = SynthGraphicsUtils.getIconWidth(expandedIcon, context); } - else { - width = SynthGraphicsUtils.getIconWidth(expandedIcon, context); - } - return width; + return SynthGraphicsUtils.getIconWidth(iconType, context); } public int getIconHeight(SynthContext context) { - int height; if (context == null) { context = getContext(tree); - height = SynthGraphicsUtils.getIconHeight(expandedIcon, context); - } - else { - height = SynthGraphicsUtils.getIconHeight(expandedIcon, context); } - return height; + return SynthGraphicsUtils.getIconHeight(iconType, context); } } } diff --git a/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java b/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java index 9c82a4fda905e..3932f7f52a107 100644 --- a/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java +++ b/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java @@ -608,7 +608,7 @@ public static void installKeybindings(UIDefaults table) { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -616,7 +616,7 @@ public static void installKeybindings(UIDefaults table) { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/classes/sun/swing/plaf/WindowsKeybindings.java b/src/java.desktop/share/classes/sun/swing/plaf/WindowsKeybindings.java index 111e76d6edb7b..c4d3f286959e6 100644 --- a/src/java.desktop/share/classes/sun/swing/plaf/WindowsKeybindings.java +++ b/src/java.desktop/share/classes/sun/swing/plaf/WindowsKeybindings.java @@ -516,7 +516,7 @@ public static void installKeybindings(UIDefaults table) { "KP_DOWN", "selectNextRow", "shift DOWN", "selectNextRowExtendSelection", "shift KP_DOWN", "selectNextRowExtendSelection", - "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl shift DOWN", "selectLastRowExtendSelection", "ctrl shift KP_DOWN", "selectNextRowExtendSelection", "ctrl DOWN", "selectNextRowChangeLead", "ctrl KP_DOWN", "selectNextRowChangeLead", @@ -524,7 +524,7 @@ public static void installKeybindings(UIDefaults table) { "KP_UP", "selectPreviousRow", "shift UP", "selectPreviousRowExtendSelection", "shift KP_UP", "selectPreviousRowExtendSelection", - "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectFirstRowExtendSelection", "ctrl shift KP_UP", "selectPreviousRowExtendSelection", "ctrl UP", "selectPreviousRowChangeLead", "ctrl KP_UP", "selectPreviousRowChangeLead", diff --git a/src/java.desktop/share/legal/lcms.md b/src/java.desktop/share/legal/lcms.md index da86a9c47ca31..02af4fff0005e 100644 --- a/src/java.desktop/share/legal/lcms.md +++ b/src/java.desktop/share/legal/lcms.md @@ -1,34 +1,29 @@ -## Little Color Management System (LCMS) v2.15 +## Little Color Management System (LCMS) v2.16 ### LCMS License

    -README.1ST file information
     
    -LittleCMS core is released under MIT License
    +MIT License
     
    ----------------------------------
    -
    -Little CMS
    -Copyright (c) 1998-2023 Marti Maria Saguer
    +Copyright (C) 1998-2023 Marti Maria Saguer
     
     Permission is hereby granted, free of charge, to any person obtaining
    -a copy of this software and associated documentation files (the
    -"Software"), to deal in the Software without restriction, including
    -without limitation the rights to use, copy, modify, merge, publish,
    -distribute, sublicense, and/or sell copies of the Software, and to
    -permit persons to whom the Software is furnished to do so, subject
    -to the following conditions:
    +a copy of this software and associated documentation files (the "Software"),
    +to deal in the Software without restriction, including without limitation
    +the rights to use, copy, modify, merge, publish, distribute, sublicense,
    +and/or sell copies of the Software, and to permit persons to whom the Software
    +is furnished to do so, subject to the following conditions:
     
    -The above copyright notice and this permission notice shall be
    -included in all copies or substantial portions of the Software.
    +The above copyright notice and this permission notice shall be included in
    +all copies or substantial portions of the Software.
     
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
    +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     
     ---------------------------------
     The below license applies to the following files:
    @@ -47,7 +42,6 @@ Users of this code must verify correctness for their application.
     ### AUTHORS File Information
     ```
     
    -
     Main Author
     ------------
     Marti Maria
    @@ -91,6 +85,7 @@ Philipp Knechtges
     Amyspark
     Lovell Fuller
     Eli Schwartz
    +Diogo Teles Sant'Anna
     
     Special Thanks
     --------------
    diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c
    index 1295d6df356d4..5cf7ee6c43629 100644
    --- a/src/java.desktop/share/native/liblcms/LCMS.c
    +++ b/src/java.desktop/share/native/liblcms/LCMS.c
    @@ -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
    @@ -177,8 +177,13 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
             }
         }
     
    +    cmsUInt32Number dwFlags = 0;
    +    if (T_EXTRA(inFormatter) > 0 && T_EXTRA(outFormatter) > 0) {
    +        dwFlags |= cmsFLAGS_COPY_ALPHA;
    +    }
    +
         sTrans = cmsCreateMultiprofileTransform(iccArray, j,
    -        inFormatter, outFormatter, renderingIntent, cmsFLAGS_COPY_ALPHA);
    +        inFormatter, outFormatter, renderingIntent, dwFlags);
     
         (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
     
    diff --git a/src/java.desktop/share/native/liblcms/cmsalpha.c b/src/java.desktop/share/native/liblcms/cmsalpha.c
    index e69259e8a5148..78d3ca6b67151 100644
    --- a/src/java.desktop/share/native/liblcms/cmsalpha.c
    +++ b/src/java.desktop/share/native/liblcms/cmsalpha.c
    @@ -431,7 +431,7 @@ static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
     
     // This function computes the distance from each component to the next one in bytes.
     static
    -void ComputeIncrementsForChunky(cmsUInt32Number Format,
    +cmsBool ComputeIncrementsForChunky(cmsUInt32Number Format,
                                     cmsUInt32Number ComponentStartingOrder[],
                                     cmsUInt32Number ComponentPointerIncrements[])
     {
    @@ -445,7 +445,7 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
     
            // Sanity check
            if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
    -           return;
    +           return FALSE;
     
             memset(channels, 0, sizeof(channels));
     
    @@ -482,13 +482,15 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
     
            for (i = 0; i < extra; i++)
                   ComponentStartingOrder[i] = channels[i + nchannels];
    +
    +       return TRUE;
     }
     
     
     
     //  On planar configurations, the distance is the stride added to any non-negative
     static
    -void ComputeIncrementsForPlanar(cmsUInt32Number Format,
    +cmsBool ComputeIncrementsForPlanar(cmsUInt32Number Format,
                                     cmsUInt32Number BytesPerPlane,
                                     cmsUInt32Number ComponentStartingOrder[],
                                     cmsUInt32Number ComponentPointerIncrements[])
    @@ -502,7 +504,7 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
     
            // Sanity check
            if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
    -           return;
    +           return FALSE;
     
            memset(channels, 0, sizeof(channels));
     
    @@ -538,29 +540,29 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
     
            for (i = 0; i < extra; i++)
                   ComponentStartingOrder[i] = channels[i + nchannels];
    +
    +       return TRUE;
     }
     
     
     
     // Dispatcher por chunky and planar RGB
     static
    -void  ComputeComponentIncrements(cmsUInt32Number Format,
    +cmsBool ComputeComponentIncrements(cmsUInt32Number Format,
                                      cmsUInt32Number BytesPerPlane,
                                      cmsUInt32Number ComponentStartingOrder[],
                                      cmsUInt32Number ComponentPointerIncrements[])
     {
            if (T_PLANAR(Format)) {
     
    -              ComputeIncrementsForPlanar(Format,  BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
    +              return ComputeIncrementsForPlanar(Format,  BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
            }
            else {
    -              ComputeIncrementsForChunky(Format,  ComponentStartingOrder, ComponentPointerIncrements);
    +              return ComputeIncrementsForChunky(Format,  ComponentStartingOrder, ComponentPointerIncrements);
            }
     
     }
     
    -
    -
     // Handles extra channels copying alpha if requested by the flags
     void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
                                                    void* out,
    @@ -595,8 +597,10 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
             return;
     
         // Compute the increments
    -    ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements);
    -    ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements);
    +    if (!ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements))
    +        return;
    +    if (!ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements))
    +        return;
     
         // Check for conversions 8, 16, half, float, dbl
         copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
    diff --git a/src/java.desktop/share/native/liblcms/cmscgats.c b/src/java.desktop/share/native/liblcms/cmscgats.c
    index 9d0aea27d7391..57725ae4731a2 100644
    --- a/src/java.desktop/share/native/liblcms/cmscgats.c
    +++ b/src/java.desktop/share/native/liblcms/cmscgats.c
    @@ -87,7 +87,7 @@ typedef enum {
             SEOF,       // End of stream
             SSYNERROR,  // Syntax error found on stream
     
    -        // Keywords
    +        // IT8 symbols
     
             SBEGIN_DATA,
             SBEGIN_DATA_FORMAT,
    @@ -95,7 +95,19 @@ typedef enum {
             SEND_DATA_FORMAT,
             SKEYWORD,
             SDATA_FORMAT_ID,
    -        SINCLUDE
    +        SINCLUDE,
    +
    +        // Cube symbols
    +
    +        SDOMAIN_MAX,
    +        SDOMAIN_MIN,
    +        S_LUT1D_SIZE,
    +        S_LUT1D_INPUT_RANGE,
    +        S_LUT3D_SIZE,
    +        S_LUT3D_INPUT_RANGE,
    +        S_LUT_IN_VIDEO_RANGE,
    +        S_LUT_OUT_VIDEO_RANGE,
    +        STITLE
     
         } SYMBOL;
     
    @@ -178,6 +190,10 @@ typedef struct struct_it8 {
             cmsUInt32Number  TablesCount;                     // How many tables in this stream
             cmsUInt32Number  nTable;                          // The actual table
     
    +        // Partser type
    +        cmsBool        IsCUBE;
    +
    +        // Tables
             TABLE Tab[MAXTABLES];
     
             // Memory management
    @@ -237,8 +253,8 @@ typedef struct {
     
        } KEYWORD;
     
    -// The keyword->symbol translation table. Sorting is required.
    -static const KEYWORD TabKeys[] = {
    +// The keyword->symbol translation tables. Sorting is required.
    +static const KEYWORD TabKeysIT8[] = {
     
             {"$INCLUDE",               SINCLUDE},   // This is an extension!
             {".INCLUDE",               SINCLUDE},   // This is an extension!
    @@ -251,7 +267,25 @@ static const KEYWORD TabKeys[] = {
             {"KEYWORD",                SKEYWORD}
             };
     
    -#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
    +#define NUMKEYS_IT8 (sizeof(TabKeysIT8)/sizeof(KEYWORD))
    +
    +static const KEYWORD TabKeysCUBE[] = {
    +
    +        {"DOMAIN_MAX",             SDOMAIN_MAX },
    +        {"DOMAIN_MIN",             SDOMAIN_MIN },
    +        {"LUT_1D_SIZE",            S_LUT1D_SIZE },
    +        {"LUT_1D_INPUT_RANGE",     S_LUT1D_INPUT_RANGE },
    +        {"LUT_3D_SIZE",            S_LUT3D_SIZE },
    +        {"LUT_3D_INPUT_RANGE",     S_LUT3D_INPUT_RANGE },
    +        {"LUT_IN_VIDEO_RANGE",     S_LUT_IN_VIDEO_RANGE },
    +        {"LUT_OUT_VIDEO_RANGE",    S_LUT_OUT_VIDEO_RANGE },
    +        {"TITLE",                  STITLE }
    +
    +};
    +
    +#define NUMKEYS_CUBE (sizeof(TabKeysCUBE)/sizeof(KEYWORD))
    +
    +
     
     // Predefined properties
     
    @@ -455,7 +489,7 @@ void StringCat(string* s, const char* c)
     static
     cmsBool isseparator(int c)
     {
    -    return (c == ' ') || (c == '\t') ;
    +    return (c == ' ') || (c == '\t');
     }
     
     // Checks whatever c is a valid identifier char
    @@ -476,7 +510,7 @@ cmsBool isidchar(int c)
     static
     cmsBool isfirstidchar(int c)
     {
    -     return !isdigit(c) && ismiddle(c);
    +     return c != '-' && !isdigit(c) && ismiddle(c);
     }
     
     // Guess whether the supplied path looks like an absolute path
    @@ -515,13 +549,13 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe
         // Already absolute?
         if (isabsolutepath(relPath)) {
     
    -        strncpy(buffer, relPath, MaxLen);
    +        memcpy(buffer, relPath, MaxLen);
             buffer[MaxLen-1] = 0;
             return TRUE;
         }
     
         // No, search for last
    -    strncpy(buffer, basePath, MaxLen);
    +    memcpy(buffer, basePath, MaxLen);
         buffer[MaxLen-1] = 0;
     
         tail = strrchr(buffer, DIR_CHAR);
    @@ -603,10 +637,10 @@ void NextCh(cmsIT8* it8)
     
     // Try to see if current identifier is a keyword, if so return the referred symbol
     static
    -SYMBOL BinSrchKey(const char *id)
    +SYMBOL BinSrchKey(const char *id, int NumKeys, const KEYWORD* TabKeys)
     {
         int l = 1;
    -    int r = NUMKEYS;
    +    int r = NumKeys;
         int x, res;
     
         while (r >= l)
    @@ -776,7 +810,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
     }
     
     
    -// Reads a string, special case to avoid infinite resursion on .include
    +// Reads a string, special case to avoid infinite recursion on .include
     static
     void InStringSymbol(cmsIT8* it8)
     {
    @@ -833,7 +867,9 @@ void InSymbol(cmsIT8* it8)
                 } while (isidchar(it8->ch));
     
     
    -            key = BinSrchKey(StringPtr(it8->id));
    +            key = BinSrchKey(StringPtr(it8->id),
    +                    it8->IsCUBE ? NUMKEYS_CUBE : NUMKEYS_IT8,
    +                    it8->IsCUBE ? TabKeysCUBE : TabKeysIT8);
                 if (key == SUNDEFINED) it8->sy = SIDENT;
                 else it8->sy = key;
     
    @@ -942,6 +978,7 @@ void InSymbol(cmsIT8* it8)
                             snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum);
                         }
     
    +                    StringClear(it8->id);
                         StringCat(it8->id, buffer);
     
                         do {
    @@ -971,7 +1008,7 @@ void InSymbol(cmsIT8* it8)
             // Next line
             case '\r':
                 NextCh(it8);
    -            if (it8 ->ch == '\n')
    +            if (it8->ch == '\n')
                     NextCh(it8);
                 it8->sy = SEOLN;
                 it8->lineno++;
    @@ -1292,7 +1329,12 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S
     
             // This may work for editing properties
     
    -        //     return SynError(it8, "duplicate key <%s>", Key);
    +        if (cmsstrcasecmp(Key, "NUMBER_OF_FIELDS") == 0 ||
    +            cmsstrcasecmp(Key, "NUMBER_OF_SETS") == 0) {
    +
    +            SynError(it8, "duplicate key <%s>", Key);
    +            return NULL;
    +        }
         }
         else {
     
    @@ -1413,6 +1455,8 @@ cmsHANDLE  CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
         it8->MemoryBlock = NULL;
         it8->MemorySink  = NULL;
     
    +    it8->IsCUBE = FALSE;
    +
         it8 ->nTable = 0;
     
         it8->ContextID = ContextID;
    @@ -1694,7 +1738,7 @@ char* GetData(cmsIT8* it8, int nSet, int nField)
         int nSamples    = t -> nSamples;
         int nPatches    = t -> nPatches;
     
    -    if (nSet >= nPatches || nField >= nSamples)
    +    if (nSet < 0 || nSet >= nPatches || nField < 0 || nField >= nSamples)
             return NULL;
     
         if (!t->Data) return NULL;
    @@ -1879,11 +1923,14 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
            WriteStr(fp, " ");
            nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
     
    -       for (i = 0; i < nSamples; i++) {
    +       if (nSamples <= t->nSamples) {
     
    -              WriteStr(fp, t->DataFormat[i]);
    -              WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t"));
    -          }
    +           for (i = 0; i < nSamples; i++) {
    +
    +               WriteStr(fp, t->DataFormat[i]);
    +               WriteStr(fp, ((i == (nSamples - 1)) ? "\n" : "\t"));
    +           }
    +       }
     
            WriteStr (fp, "END_DATA_FORMAT\n");
     }
    @@ -1893,39 +1940,42 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
     static
     void WriteData(SAVESTREAM* fp, cmsIT8* it8)
     {
    -       int  i, j;
    +       int  i, j, nPatches;
            TABLE* t = GetTable(it8);
     
            if (!t->Data) return;
     
            WriteStr (fp, "BEGIN_DATA\n");
     
    -       t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
    +       nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
     
    -       for (i = 0; i < t-> nPatches; i++) {
    +       if (nPatches <= t->nPatches) {
     
    -              WriteStr(fp, " ");
    +           for (i = 0; i < nPatches; i++) {
     
    -              for (j = 0; j < t->nSamples; j++) {
    +               WriteStr(fp, " ");
     
    -                     char *ptr = t->Data[i*t->nSamples+j];
    +               for (j = 0; j < t->nSamples; j++) {
     
    -                     if (ptr == NULL) WriteStr(fp, "\"\"");
    -                     else {
    -                         // If value contains whitespace, enclose within quote
    +                   char* ptr = t->Data[i * t->nSamples + j];
     
    -                         if (strchr(ptr, ' ') != NULL) {
    +                   if (ptr == NULL) WriteStr(fp, "\"\"");
    +                   else {
    +                       // If value contains whitespace, enclose within quote
     
    -                             WriteStr(fp, "\"");
    -                             WriteStr(fp, ptr);
    -                             WriteStr(fp, "\"");
    -                         }
    -                         else
    -                            WriteStr(fp, ptr);
    -                     }
    +                       if (strchr(ptr, ' ') != NULL) {
     
    -                     WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t"));
    -              }
    +                           WriteStr(fp, "\"");
    +                           WriteStr(fp, ptr);
    +                           WriteStr(fp, "\"");
    +                       }
    +                       else
    +                           WriteStr(fp, ptr);
    +                   }
    +
    +                   WriteStr(fp, ((j == (t->nSamples - 1)) ? "\n" : "\t"));
    +               }
    +           }
            }
            WriteStr (fp, "END_DATA\n");
     }
    @@ -1946,15 +1996,29 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
     
         for (i=0; i < it8 ->TablesCount; i++) {
     
    -            cmsIT8SetTable(hIT8, i);
    -            WriteHeader(it8, &sd);
    -            WriteDataFormat(&sd, it8);
    -            WriteData(&sd, it8);
    +        TABLE* t;
    +
    +        if (cmsIT8SetTable(hIT8, i) < 0) goto Error;
    +
    +        /**
    +        * Check for wrong data
    +        */
    +        t = GetTable(it8);
    +        if (t->Data == NULL) goto Error;
    +        if (t->DataFormat == NULL) goto Error;
    +
    +        WriteHeader(it8, &sd);
    +        WriteDataFormat(&sd, it8);
    +        WriteData(&sd, it8);
         }
     
         if (fclose(sd.stream) != 0) return FALSE;
    -
         return TRUE;
    +
    +Error:
    +    fclose(sd.stream);
    +    return FALSE;
    +
     }
     
     
    @@ -2331,78 +2395,72 @@ void CookPointers(cmsIT8* it8)
         int idField, i;
         char* Fld;
         cmsUInt32Number j;
    -    cmsUInt32Number nOldTable = it8 ->nTable;
    +    cmsUInt32Number nOldTable = it8->nTable;
     
    -    for (j=0; j < it8 ->TablesCount; j++) {
    +    for (j = 0; j < it8->TablesCount; j++) {
     
    -    TABLE* t = it8 ->Tab + j;
    +        TABLE* t = it8->Tab + j;
     
    -    t -> SampleID = 0;
    -    it8 ->nTable = j;
    +        t->SampleID = 0;
    +        it8->nTable = j;
     
    -    for (idField = 0; idField < t -> nSamples; idField++)
    -    {
    -        if (t ->DataFormat == NULL){
    -            SynError(it8, "Undefined DATA_FORMAT");
    -            return;
    -        }
    +        for (idField = 0; idField < t->nSamples; idField++)
    +        {
    +            if (t->DataFormat == NULL) {
    +                SynError(it8, "Undefined DATA_FORMAT");
    +                return;
    +            }
     
    -        Fld = t->DataFormat[idField];
    -        if (!Fld) continue;
    +            Fld = t->DataFormat[idField];
    +            if (!Fld) continue;
     
     
    -        if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
    +            if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
     
    -            t -> SampleID = idField;
    -        }
    +                t->SampleID = idField;
    +            }
     
    -        // "LABEL" is an extension. It keeps references to forward tables
    +            // "LABEL" is an extension. It keeps references to forward tables
     
    -        if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
    +            if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
     
    -            // Search for table references...
    -            for (i = 0; i < t->nPatches; i++) {
    +                // Search for table references...
    +                for (i = 0; i < t->nPatches; i++) {
     
    -                char* Label = GetData(it8, i, idField);
    +                    char* Label = GetData(it8, i, idField);
     
    -                if (Label) {
    +                    if (Label) {
     
    -                    cmsUInt32Number k;
    +                        cmsUInt32Number k;
     
    -                    // This is the label, search for a table containing
    -                    // this property
    +                        // This is the label, search for a table containing
    +                        // this property
     
    -                    for (k = 0; k < it8->TablesCount; k++) {
    +                        for (k = 0; k < it8->TablesCount; k++) {
     
    -                        TABLE* Table = it8->Tab + k;
    -                        KEYVALUE* p;
    +                            TABLE* Table = it8->Tab + k;
    +                            KEYVALUE* p;
     
    -                        if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
    +                            if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
     
    -                            // Available, keep type and table
    -                            char Buffer[256];
    +                                // Available, keep type and table
    +                                char Buffer[256];
     
    -                            char* Type = p->Value;
    -                            int  nTable = (int)k;
    +                                char* Type = p->Value;
    +                                int  nTable = (int)k;
     
    -                            snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
    +                                snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
     
    -                            SetData(it8, i, idField, Buffer);
    +                                SetData(it8, i, idField, Buffer);
    +                            }
                             }
                         }
    -
    -
                     }
    -
                 }
    -
    -
             }
    -
    -    }
         }
     
    -    it8 ->nTable = nOldTable;
    +    it8->nTable = nOldTable;
     }
     
     // Try to infere if the file is a CGATS/IT8 file at all. Read first line
    @@ -2493,7 +2551,7 @@ cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm
         if (it8->MemoryBlock == NULL)
         {
             cmsIT8Free(hIT8);
    -        return FALSE;
    +        return NULL;
         }
     
         strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
    @@ -2505,7 +2563,7 @@ cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm
         if (!ParseIT8(it8, type-1)) {
     
             cmsIT8Free(hIT8);
    -        return FALSE;
    +        return NULL;
         }
     
         CookPointers(it8);
    @@ -2602,17 +2660,17 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN
         }
     
     
    -        Props = (char**)AllocChunk(it8, sizeof(char*) * n);
    -        if (Props != NULL) {
    -
    -                // Pass#2 - Fill pointers
    -                n = 0;
    -                for (p = t->HeaderList; p != NULL; p = p->Next) {
    -                        Props[n++] = p->Keyword;
    -                }
    +    Props = (char**)AllocChunk(it8, sizeof(char*) * n);
    +    if (Props != NULL) {
     
    +        // Pass#2 - Fill pointers
    +        n = 0;
    +        for (p = t->HeaderList; p != NULL; p = p->Next) {
    +            Props[n++] = p->Keyword;
             }
    -        *PropertyNames = Props;
    +
    +    }
    +    *PropertyNames = Props;
     
         return n;
     }
    @@ -2972,3 +3030,236 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
         it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
     }
     
    +
    +static
    +cmsBool ReadNumbers(cmsIT8* cube, int n, cmsFloat64Number* arr)
    +{
    +    int i;
    +
    +    for (i = 0; i < n; i++) {
    +
    +        if (cube->sy == SINUM)
    +            arr[i] = cube->inum;
    +        else
    +            if (cube->sy == SDNUM)
    +                arr[i] = cube->dnum;
    +            else
    +                return SynError(cube, "Number expected");
    +
    +        InSymbol(cube);
    +    }
    +
    +    return CheckEOLN(cube);
    +}
    +
    +static
    +cmsBool ParseCube(cmsIT8* cube, cmsStage** Shaper, cmsStage** CLUT, char title[])
    +{
    +    cmsFloat64Number domain_min[3] = { 0, 0, 0 };
    +    cmsFloat64Number domain_max[3] = { 1.0, 1.0, 1.0 };
    +    cmsFloat64Number check_0_1[2] = { 0, 1.0 };
    +    int shaper_size = 0;
    +    int lut_size = 0;
    +    int i;
    +
    +    InSymbol(cube);
    +
    +    while (cube->sy != SEOF) {
    +        switch (cube->sy)
    +        {
    +        // Set profile description
    +        case STITLE:
    +            InSymbol(cube);
    +            if (!Check(cube, SSTRING, "Title string expected")) return FALSE;
    +            memcpy(title, StringPtr(cube->str), MAXSTR);
    +            title[MAXSTR - 1] = 0;
    +            InSymbol(cube);
    +            break;
    +
    +        // Define domain
    +        case SDOMAIN_MIN:
    +            InSymbol(cube);
    +            if (!ReadNumbers(cube, 3, domain_min)) return FALSE;
    +            break;
    +
    +        case SDOMAIN_MAX:
    +            InSymbol(cube);
    +            if (!ReadNumbers(cube, 3, domain_max)) return FALSE;
    +            break;
    +
    +        // Define shaper
    +        case S_LUT1D_SIZE:
    +            InSymbol(cube);
    +            if (!Check(cube, SINUM, "Shaper size expected")) return FALSE;
    +            shaper_size = cube->inum;
    +            InSymbol(cube);
    +            break;
    +
    +        // Deefine CLUT
    +        case S_LUT3D_SIZE:
    +            InSymbol(cube);
    +            if (!Check(cube, SINUM, "LUT size expected")) return FALSE;
    +            lut_size = cube->inum;
    +            InSymbol(cube);
    +            break;
    +
    +        // Range. If present, has to be 0..1.0
    +        case S_LUT1D_INPUT_RANGE:
    +        case S_LUT3D_INPUT_RANGE:
    +            InSymbol(cube);
    +            if (!ReadNumbers(cube, 2, check_0_1)) return FALSE;
    +            if (check_0_1[0] != 0 || check_0_1[1] != 1.0) {
    +                return SynError(cube, "Unsupported format");
    +            }
    +            break;
    +
    +        case SEOLN:
    +            InSymbol(cube);
    +            break;
    +
    +        default:
    +        case S_LUT_IN_VIDEO_RANGE:
    +        case S_LUT_OUT_VIDEO_RANGE:
    +            return SynError(cube, "Unsupported format");
    +
    +            // Read and create tables
    +        case SINUM:
    +        case SDNUM:
    +
    +            if (shaper_size > 0) {
    +
    +                cmsToneCurve* curves[3];
    +                cmsFloat32Number* shapers = (cmsFloat32Number*)_cmsMalloc(cube->ContextID, 3 * shaper_size * sizeof(cmsFloat32Number));
    +                if (shapers == NULL) return FALSE;
    +
    +                for (i = 0; i < shaper_size; i++) {
    +
    +                    cmsFloat64Number nums[3];
    +
    +                    if (!ReadNumbers(cube, 3, nums)) return FALSE;
    +
    +                    shapers[i + 0]               = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0]));
    +                    shapers[i + 1 * shaper_size] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1]));
    +                    shapers[i + 2 * shaper_size] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2]));
    +                }
    +
    +                for (i = 0; i < 3; i++) {
    +
    +                    curves[i] = cmsBuildTabulatedToneCurveFloat(cube->ContextID, shaper_size,
    +                        &shapers[i * shaper_size]);
    +                    if (curves[i] == NULL) return FALSE;
    +                }
    +
    +                *Shaper = cmsStageAllocToneCurves(cube->ContextID, 3, curves);
    +
    +                cmsFreeToneCurveTriple(curves);
    +            }
    +
    +            if (lut_size > 0) {
    +
    +                int nodes = lut_size * lut_size * lut_size;
    +
    +                cmsFloat32Number* lut_table = _cmsMalloc(cube->ContextID, nodes * 3 * sizeof(cmsFloat32Number));
    +                if (lut_table == NULL) return FALSE;
    +
    +                for (i = 0; i < nodes; i++) {
    +
    +                    cmsFloat64Number nums[3];
    +
    +                    if (!ReadNumbers(cube, 3, nums)) return FALSE;
    +
    +                    lut_table[i * 3 + 2] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0]));
    +                    lut_table[i * 3 + 1] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1]));
    +                    lut_table[i * 3 + 0] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2]));
    +                }
    +
    +                *CLUT = cmsStageAllocCLutFloat(cube->ContextID, lut_size, 3, 3, lut_table);
    +                _cmsFree(cube->ContextID, lut_table);
    +            }
    +
    +            if (!Check(cube, SEOF, "Extra symbols found in file")) return FALSE;
    +        }
    +    }
    +
    +    return TRUE;
    +}
    +
    +// Share the parser to read .cube format and create RGB devicelink profiles
    +cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName)
    +{
    +    cmsHPROFILE hProfile = NULL;
    +    cmsIT8* cube = NULL;
    +    cmsPipeline* Pipeline = NULL;
    +    cmsStage* CLUT = NULL;
    +    cmsStage* Shaper = NULL;
    +    cmsMLU* DescriptionMLU = NULL;
    +    char title[MAXSTR];
    +
    +    _cmsAssert(cFileName != NULL);
    +
    +    cube = (cmsIT8*) cmsIT8Alloc(ContextID);
    +    if (!cube) return NULL;
    +
    +    cube->IsCUBE = TRUE;
    +    cube->FileStack[0]->Stream = fopen(cFileName, "rt");
    +
    +    if (!cube->FileStack[0]->Stream) goto Done;
    +
    +    strncpy(cube->FileStack[0]->FileName, cFileName, cmsMAX_PATH - 1);
    +    cube->FileStack[0]->FileName[cmsMAX_PATH - 1] = 0;
    +
    +    if (!ParseCube(cube, &Shaper, &CLUT, title)) goto Done;
    +
    +    // Success on parsing, let's create the profile
    +    hProfile = cmsCreateProfilePlaceholder(ContextID);
    +    if (!hProfile) goto Done;
    +
    +    cmsSetProfileVersion(hProfile, 4.4);
    +
    +    cmsSetDeviceClass(hProfile, cmsSigLinkClass);
    +    cmsSetColorSpace(hProfile,  cmsSigRgbData);
    +    cmsSetPCS(hProfile,         cmsSigRgbData);
    +
    +    cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL);
    +
    +    // Creates a Pipeline to hold CLUT and shaper
    +    Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
    +    if (Pipeline == NULL) goto Done;
    +
    +    // Populates the pipeline
    +    if (Shaper != NULL) {
    +        if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Shaper))
    +            goto Done;
    +    }
    +
    +    if (CLUT != NULL) {
    +        if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT))
    +            goto Done;
    +    }
    +
    +    // Propagate the description. We put no copyright because we know
    +    // nothing on the copyrighted state of the .cube
    +    DescriptionMLU = cmsMLUalloc(ContextID, 1);
    +    if (!cmsMLUsetUTF8(DescriptionMLU, cmsNoLanguage, cmsNoCountry, title)) goto Done;
    +
    +    // Flush the tags
    +    if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Done;
    +    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, (void*)Pipeline)) goto Done;
    +
    +Done:
    +
    +    if (DescriptionMLU != NULL)
    +        cmsMLUfree(DescriptionMLU);
    +
    +    if (Pipeline != NULL)
    +        cmsPipelineFree(Pipeline);
    +
    +    cmsIT8Free((cmsHANDLE) cube);
    +
    +    return hProfile;
    +}
    +
    +cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName)
    +{
    +    return cmsCreateDeviceLinkFromCubeFileTHR(NULL, cFileName);
    +}
    diff --git a/src/java.desktop/share/native/liblcms/cmscnvrt.c b/src/java.desktop/share/native/liblcms/cmscnvrt.c
    index b73d594f2ec94..d18865b15b9a3 100644
    --- a/src/java.desktop/share/native/liblcms/cmscnvrt.c
    +++ b/src/java.desktop/share/native/liblcms/cmscnvrt.c
    @@ -263,7 +263,7 @@ cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad)
     
     // Compute a CHAD based on a given temperature
     static
    -    void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
    +void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
     {
         cmsCIEXYZ White;
         cmsCIExyY ChromaticityOfWhite;
    @@ -744,6 +744,16 @@ int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSRE
         return TRUE;
     }
     
    +
    +// Check whatever the profile is a CMYK->CMYK devicelink
    +static
    +cmsBool is_cmyk_devicelink(cmsHPROFILE hProfile)
    +{
    +    return cmsGetDeviceClass(hProfile) == cmsSigLinkClass &&
    +            cmsGetColorSpace(hProfile) == cmsSigCmykData &&
    +            cmsGetColorSpace(hProfile) == cmsSigCmykData;
    +}
    +
     // This is the entry for black-preserving K-only intents, which are non-ICC
     static
     cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
    @@ -776,14 +786,16 @@ cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
         lastProfilePos = nProfiles - 1;
         hLastProfile = hProfiles[lastProfilePos];
     
    -    while (lastProfilePos > 1)
    +    // Skip CMYK->CMYK devicelinks on ending
    +    while (is_cmyk_devicelink(hLastProfile))
         {
    -        hLastProfile = hProfiles[--lastProfilePos];
    -        if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
    -            cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
    +        if (lastProfilePos < 2)
                 break;
    +
    +        hLastProfile = hProfiles[--lastProfilePos];
         }
     
    +
         preservationProfilesCount = lastProfilePos + 1;
     
         // Check for non-cmyk profiles
    @@ -800,7 +812,7 @@ cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
     
         // Create a LUT holding normal ICC transform
         bp.cmyk2cmyk = DefaultICCintents(ContextID,
    -                                     preservationProfilesCount,
    +        preservationProfilesCount,
             ICCIntents,
             hProfiles,
             BPC,
    @@ -812,7 +824,7 @@ cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
         // Now, compute the tone curve
         bp.KTone = _cmsBuildKToneCurve(ContextID,
             4096,
    -                                    preservationProfilesCount,
    +        preservationProfilesCount,
             ICCIntents,
             hProfiles,
             BPC,
    @@ -1002,12 +1014,13 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext     ContextID,
         lastProfilePos = nProfiles - 1;
         hLastProfile = hProfiles[lastProfilePos];
     
    -    while (lastProfilePos > 1)
    +    // Skip CMYK->CMYK devicelinks on ending
    +    while (is_cmyk_devicelink(hLastProfile))
         {
    -        hLastProfile = hProfiles[--lastProfilePos];
    -        if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
    -            cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
    +        if (lastProfilePos < 2)
                 break;
    +
    +        hLastProfile = hProfiles[--lastProfilePos];
         }
     
         preservationProfilesCount = lastProfilePos + 1;
    @@ -1177,8 +1190,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
         cmsIntentsList* pt;
         cmsUInt32Number nIntents;
     
    -
    -    for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next)
    +    for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
         {
             if (nIntents < nMax) {
                 if (Codes != NULL)
    @@ -1191,7 +1203,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
             nIntents++;
         }
     
    -    for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
    +    for (pt = ctx->Intents; pt != NULL; pt = pt -> Next)
         {
             if (nIntents < nMax) {
                 if (Codes != NULL)
    @@ -1203,6 +1215,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
     
             nIntents++;
         }
    +
         return nIntents;
     }
     
    diff --git a/src/java.desktop/share/native/liblcms/cmserr.c b/src/java.desktop/share/native/liblcms/cmserr.c
    index 739cc0b2c98e8..9fb7db89c9a6c 100644
    --- a/src/java.desktop/share/native/liblcms/cmserr.c
    +++ b/src/java.desktop/share/native/liblcms/cmserr.c
    @@ -101,7 +101,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
     //
     // This is the interface to low-level memory management routines. By default a simple
     // wrapping to malloc/free/realloc is provided, although there is a limit on the max
    -// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent
    +// amount of memory that can be reclaimed. This is mostly as a safety feature to prevent
     // bogus or evil code to allocate huge blocks that otherwise lcms would never need.
     
     #define MAX_MEMORY_FOR_ALLOC  ((cmsUInt32Number)(1024U*1024U*512U))
    @@ -121,7 +121,8 @@ cmsBool   _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug
     static
     void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
     {
    -    if (size > MAX_MEMORY_FOR_ALLOC) return NULL;  // Never allow over maximum
    +    // Never allow 0 or over maximum
    +    if (size == 0 || size > MAX_MEMORY_FOR_ALLOC) return NULL;
     
         return (void*) malloc(size);
     
    @@ -263,7 +264,7 @@ cmsBool  _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data)
     
         // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.
         // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the
    -    // context internal data should be malloce'd by using those functions.
    +    // context internal data should be malloc'ed by using those functions.
         if (Data == NULL) {
     
            struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID;
    diff --git a/src/java.desktop/share/native/liblcms/cmsgamma.c b/src/java.desktop/share/native/liblcms/cmsgamma.c
    index 08409434064a3..8e489a43c5533 100644
    --- a/src/java.desktop/share/native/liblcms/cmsgamma.c
    +++ b/src/java.desktop/share/native/liblcms/cmsgamma.c
    @@ -329,6 +329,10 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEnt
             return p;
     
     Error:
    +    for (i=0; i < nSegments; i++) {
    +        if (p ->Segments && p ->Segments[i].SampledPoints) _cmsFree(ContextID, p ->Segments[i].SampledPoints);
    +        if (p ->SegInterp && p ->SegInterp[i]) _cmsFree(ContextID, p ->SegInterp[i]);
    +    }
         if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp);
         if (p -> Segments) _cmsFree(ContextID, p -> Segments);
         if (p -> Evals) _cmsFree(ContextID, p -> Evals);
    @@ -622,10 +626,16 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
         case 6:
             e = Params[1]*R + Params[2];
     
    -        if (e < 0)
    -            Val = Params[3];
    -        else
    -            Val = pow(e, Params[0]) + Params[3];
    +        // On gamma 1.0, don't clamp
    +        if (Params[0] == 1.0) {
    +            Val = e + Params[3];
    +        }
    +        else {
    +            if (e < 0)
    +                Val = Params[3];
    +            else
    +                Val = pow(e, Params[0]) + Params[3];
    +        }
             break;
     
         // ((Y - c) ^1/Gamma - b) / a
    @@ -1520,13 +1530,13 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num
         return (sum / n);   // The mean
     }
     
    +// Retrieve segments on tone curves
     
    -// Retrieve parameters on one-segment tone curves
    -
    -cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t)
    +const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t)
     {
         _cmsAssert(t != NULL);
     
    -    if (t->nSegments != 1) return NULL;
    -    return t->Segments[0].Params;
    +    if (n < 0 || n >= (cmsInt32Number) t->nSegments) return NULL;
    +    return t->Segments + n;
     }
    +
    diff --git a/src/java.desktop/share/native/liblcms/cmsgmt.c b/src/java.desktop/share/native/liblcms/cmsgmt.c
    index 60a01aa50882e..e9ee73b52cd0d 100644
    --- a/src/java.desktop/share/native/liblcms/cmsgmt.c
    +++ b/src/java.desktop/share/native/liblcms/cmsgmt.c
    @@ -248,7 +248,7 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
         cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
         cmsFloat64Number dE1, dE2, ErrorRatio;
     
    -    // Assume in-gamut by default.
    +    // Assume in-gamut by default. NEVER READ, USED FOR DEBUG PURPOSES.
         ErrorRatio = 1.0;
     
         // Convert input to Lab
    @@ -625,7 +625,7 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
     // Actually, doing that "well" is quite hard, since every component may behave completely different.
     // Since the true point of this function is to detect suitable optimizations, I am imposing some requirements
     // that simplifies things: only RGB, and only profiles that can got in both directions.
    -// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma.
    +// The algorithm obtains Y from a synthetical gray R=G=B. Then least squares fitting is used to estimate gamma.
     // For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned.
     
     cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold)
    diff --git a/src/java.desktop/share/native/liblcms/cmsio0.c b/src/java.desktop/share/native/liblcms/cmsio0.c
    index 6763970f61937..05baa9392e21a 100644
    --- a/src/java.desktop/share/native/liblcms/cmsio0.c
    +++ b/src/java.desktop/share/native/liblcms/cmsio0.c
    @@ -560,6 +560,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
         // Set default version
         Icc ->Version =  0x02100000;
     
    +    // Set default CMM (that's me!)
    +    Icc ->CMM = lcmsSignature;
    +
    +    // Set default creator
    +    // Created by LittleCMS (that's me!)
    +    Icc ->creator = lcmsSignature;
    +
    +    // Set default platform
    +#ifdef CMS_IS_WINDOWS_
    +    Icc ->platform = cmsSigMicrosoft;
    +#else
    +    Icc ->platform = cmsSigMacintosh;
    +#endif
    +
         // Set default device class
         Icc->DeviceClass = cmsSigDisplayClass;
     
    @@ -813,11 +827,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
         }
     
         // Adjust endianness of the used parameters
    +    Icc -> CMM             = _cmsAdjustEndianess32(Header.cmmId);
         Icc -> DeviceClass     = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
         Icc -> ColorSpace      = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.colorSpace);
         Icc -> PCS             = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.pcs);
     
         Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
    +    Icc -> platform        = (cmsPlatformSignature)_cmsAdjustEndianess32(Header.platform);
         Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
         Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
         Icc -> model           = _cmsAdjustEndianess32(Header.model);
    @@ -922,7 +938,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
         cmsUInt32Number Count;
     
         Header.size        = _cmsAdjustEndianess32(UsedSpace);
    -    Header.cmmId       = _cmsAdjustEndianess32(lcmsSignature);
    +    Header.cmmId       = _cmsAdjustEndianess32(Icc ->CMM);
         Header.version     = _cmsAdjustEndianess32(Icc ->Version);
     
         Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass);
    @@ -934,11 +950,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
     
         Header.magic       = _cmsAdjustEndianess32(cmsMagicNumber);
     
    -#ifdef CMS_IS_WINDOWS_
    -    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft);
    -#else
    -    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh);
    -#endif
    +    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(Icc -> platform);
     
         Header.flags        = _cmsAdjustEndianess32(Icc -> flags);
         Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
    @@ -954,8 +966,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
         Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
         Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
     
    -    // Created by LittleCMS (that's me!)
    -    Header.creator      = _cmsAdjustEndianess32(lcmsSignature);
    +    Header.creator      = _cmsAdjustEndianess32(Icc ->creator);
     
         memset(&Header.reserved, 0, sizeof(Header.reserved));
     
    diff --git a/src/java.desktop/share/native/liblcms/cmsio1.c b/src/java.desktop/share/native/liblcms/cmsio1.c
    index bd8a832ac40cc..e42d4d3898730 100644
    --- a/src/java.desktop/share/native/liblcms/cmsio1.c
    +++ b/src/java.desktop/share/native/liblcms/cmsio1.c
    @@ -607,7 +607,7 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo
         return NULL;
     }
     
    -// Create an output MPE LUT from agiven profile. Version mismatches are handled here
    +// Create an output MPE LUT from a given profile. Version mismatches are handled here
     cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent)
     {
         cmsTagTypeSignature OriginalType;
    @@ -1056,3 +1056,13 @@ cmsUInt32Number  CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoT
     
         return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
     }
    +
    +cmsUInt32Number  CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info,
    +                                                          const char LanguageCode[3], const char CountryCode[3],
    +                                                          char* Buffer, cmsUInt32Number BufferSize)
    +{
    +    const cmsMLU* mlu = GetInfo(hProfile, Info);
    +    if (mlu == NULL) return 0;
    +
    +    return cmsMLUgetUTF8(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
    +}
    diff --git a/src/java.desktop/share/native/liblcms/cmslut.c b/src/java.desktop/share/native/liblcms/cmslut.c
    index 24114632ad0a9..b544c94862592 100644
    --- a/src/java.desktop/share/native/liblcms/cmslut.c
    +++ b/src/java.desktop/share/native/liblcms/cmslut.c
    @@ -504,6 +504,9 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b)
             if (rv > UINT_MAX / dim) return 0;
         }
     
    +    // Again, prevent overflow
    +    if (rv > UINT_MAX / 15) return 0;
    +
         return rv;
     }
     
    @@ -843,7 +846,13 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
         cmsUInt32Number nInputs, nOutputs;
         cmsUInt32Number* nSamples;
         cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
    -    _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
    +    _cmsStageCLutData* clut;
    +
    +    if (mpe == NULL) return FALSE;
    +
    +    clut = (_cmsStageCLutData*)mpe->Data;
    +
    +    if (clut == NULL) return FALSE;
     
         nSamples = clut->Params ->nSamples;
         nInputs  = clut->Params ->nInputs;
    diff --git a/src/java.desktop/share/native/liblcms/cmsnamed.c b/src/java.desktop/share/native/liblcms/cmsnamed.c
    index 0428018023008..d3cd97d4aea5f 100644
    --- a/src/java.desktop/share/native/liblcms/cmsnamed.c
    +++ b/src/java.desktop/share/native/liblcms/cmsnamed.c
    @@ -229,17 +229,145 @@ void strFrom16(char str[3], cmsUInt16Number n)
         str[0] = (char)(n >> 8);
         str[1] = (char)n;
         str[2] = (char)0;
    +}
    +
    +
    +// Convert from UTF8 to wchar, returns len.
    +static
    +cmsUInt32Number decodeUTF8(wchar_t* out, const char* in)
    +{
    +    cmsUInt32Number codepoint = 0;
    +    cmsUInt32Number size = 0;
    +
    +    while (*in)
    +    {
    +        cmsUInt8Number ch = (cmsUInt8Number) *in;
    +
    +        if (ch <= 0x7f)
    +        {
    +            codepoint = ch;
    +        }
    +        else if (ch <= 0xbf)
    +        {
    +            codepoint = (codepoint << 6) | (ch & 0x3f);
    +        }
    +        else if (ch <= 0xdf)
    +        {
    +            codepoint = ch & 0x1f;
    +        }
    +        else if (ch <= 0xef)
    +        {
    +            codepoint = ch & 0x0f;
    +        }
    +        else
    +        {
    +            codepoint = ch & 0x07;
    +        }
    +
    +        in++;
     
    +        if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
    +        {
    +            if (sizeof(wchar_t) > 2)
    +            {
    +                if (out) *out++ = (wchar_t) codepoint;
    +                size++;
    +            }
    +            else
    +                if (codepoint > 0xffff)
    +                {
    +                    if (out)
    +                    {
    +                        *out++ = (wchar_t)(0xd800 + (codepoint >> 10));
    +                        *out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff));
    +                        size += 2;
    +                    }
    +                }
    +                else
    +                    if (codepoint < 0xd800 || codepoint >= 0xe000)
    +                    {
    +                        if (out) *out++ = (wchar_t) codepoint;
    +                        size++;
    +                    }
    +        }
    +    }
    +
    +    return size;
    +}
    +
    +// Convert from wchar_t to UTF8
    +static
    +cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wchars, cmsUInt32Number max_chars)
    +{
    +    cmsUInt32Number codepoint = 0;
    +    cmsUInt32Number size = 0;
    +    cmsUInt32Number len_w = 0;
    +
    +    while (*in && len_w < max_wchars)
    +    {
    +        if (*in >= 0xd800 && *in <= 0xdbff)
    +            codepoint = ((*in - 0xd800) << 10) + 0x10000;
    +        else
    +        {
    +            if (*in >= 0xdc00 && *in <= 0xdfff)
    +                codepoint |= *in - 0xdc00;
    +            else
    +                codepoint = *in;
    +
    +            if (codepoint <= 0x7f)
    +            {
    +                if (out && (size + 1 < max_chars)) *out++ = (char)codepoint;
    +                size++;
    +            }
    +
    +            else if (codepoint <= 0x7ff)
    +            {
    +                if (out && (max_chars > 0) && (size + 2 < max_chars))
    +                {
    +                    *out++ = (char)(cmsUInt32Number)(0xc0 | ((codepoint >> 6) & 0x1f));
    +                    *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
    +                }
    +                size += 2;
    +            }
    +            else if (codepoint <= 0xffff)
    +            {
    +                if (out && (max_chars > 0) && (size + 3 < max_chars))
    +                {
    +                    *out++ = (char)(cmsUInt32Number)(0xe0 | ((codepoint >> 12) & 0x0f));
    +                    *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f));
    +                    *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
    +                }
    +                size += 3;
    +            }
    +            else
    +            {
    +                if (out && (max_chars > 0) && (size + 4 < max_chars))
    +                {
    +                    *out++ = (char)(cmsUInt32Number)(0xf0 | ((codepoint >> 18) & 0x07));
    +                    *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 12) & 0x3f));
    +                    *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f));
    +                    *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
    +                }
    +                size += 4;
    +            }
    +
    +            codepoint = 0;
    +        }
    +
    +        in++; len_w++;
    +    }
    +
    +    return size;
     }
     
     // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
     // In the case the user explicitly sets an empty string, we force a \0
     cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
     {
    -    cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
    +    cmsUInt32Number i, len = (cmsUInt32Number)strlen(ASCIIString);
         wchar_t* WStr;
         cmsBool  rc;
    -    cmsUInt16Number Lang  = strTo16(LanguageCode);
    +    cmsUInt16Number Lang = strTo16(LanguageCode);
         cmsUInt16Number Cntry = strTo16(CountryCode);
     
         if (mlu == NULL) return FALSE;
    @@ -247,22 +375,56 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const
         // len == 0 would prevent operation, so we set a empty string pointing to zero
         if (len == 0)
         {
    -        len = 1;
    +        wchar_t empty = 0;
    +        return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry);
         }
     
    -    WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len,  sizeof(wchar_t));
    +    WStr = (wchar_t*)_cmsCalloc(mlu->ContextID, len, sizeof(wchar_t));
         if (WStr == NULL) return FALSE;
     
    -    for (i=0; i < len; i++)
    -        WStr[i] = (wchar_t) ASCIIString[i];
    +    for (i = 0; i < len; i++)
    +        WStr[i] = (wchar_t)ASCIIString[i];
     
    -    rc = AddMLUBlock(mlu, len  * sizeof(wchar_t), WStr, Lang, Cntry);
    +    rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
     
    -    _cmsFree(mlu ->ContextID, WStr);
    +    _cmsFree(mlu->ContextID, WStr);
         return rc;
     
     }
     
    +// Add an UTF8 entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
    +// In the case the user explicitly sets an empty string, we force a \0
    +cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* UTF8String)
    +{
    +    cmsUInt32Number UTF8len;
    +    wchar_t* WStr;
    +    cmsBool  rc;
    +    cmsUInt16Number Lang  = strTo16(LanguageCode);
    +    cmsUInt16Number Cntry = strTo16(CountryCode);
    +
    +    if (mlu == NULL) return FALSE;
    +
    +    if (*UTF8String == '\0')
    +    {
    +        wchar_t empty = 0;
    +        return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry);
    +    }
    +
    +    // Len excluding terminator 0
    +    UTF8len = decodeUTF8(NULL, UTF8String);
    +
    +    // Get space for dest
    +    WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, UTF8len,  sizeof(wchar_t));
    +    if (WStr == NULL) return FALSE;
    +
    +    decodeUTF8(WStr, UTF8String);
    +
    +    rc = AddMLUBlock(mlu, UTF8len  * sizeof(wchar_t), WStr, Lang, Cntry);
    +
    +    _cmsFree(mlu ->ContextID, WStr);
    +    return rc;
    +}
    +
     // We don't need any wcs support library
     static
     cmsUInt32Number mywcslen(const wchar_t *s)
    @@ -401,7 +563,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
     
         if (v->StrW + v->Len > mlu->PoolSize) return NULL;
     
    -    return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
    +    return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
     }
     
     
    @@ -439,10 +601,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
         // Precess each character
         for (i=0; i < ASCIIlen; i++) {
     
    -        if (Wide[i] == 0)
    -            Buffer[i] = 0;
    +        wchar_t wc = Wide[i];
    +
    +        if (wc < 0xff)
    +            Buffer[i] = (char)wc;
             else
    -            Buffer[i] = (char) Wide[i];
    +            Buffer[i] = '?';
         }
     
         // We put a termination "\0"
    @@ -450,6 +614,46 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
         return ASCIIlen + 1;
     }
     
    +
    +// Obtain a UTF8 representation of the wide string. Setting buffer to NULL returns the len
    +cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu,
    +                                       const char LanguageCode[3], const char CountryCode[3],
    +                                       char* Buffer, cmsUInt32Number BufferSize)
    +{
    +    const wchar_t *Wide;
    +    cmsUInt32Number  StrLen = 0;
    +    cmsUInt32Number UTF8len;
    +
    +    cmsUInt16Number Lang  = strTo16(LanguageCode);
    +    cmsUInt16Number Cntry = strTo16(CountryCode);
    +
    +    // Sanitize
    +    if (mlu == NULL) return 0;
    +
    +    // Get WideChar
    +    Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
    +    if (Wide == NULL) return 0;
    +
    +    UTF8len = encodeUTF8(NULL, Wide, StrLen / sizeof(wchar_t), BufferSize);
    +
    +    // Maybe we want only to know the len?
    +    if (Buffer == NULL) return UTF8len + 1; // Note the zero at the end
    +
    +    // No buffer size means no data
    +    if (BufferSize <= 0) return 0;
    +
    +    // Some clipping may be required
    +    if (BufferSize < UTF8len + 1)
    +        UTF8len = BufferSize - 1;
    +
    +    // Process it
    +    encodeUTF8(Buffer, Wide, StrLen / sizeof(wchar_t), BufferSize);
    +
    +    // We put a termination "\0"
    +    Buffer[UTF8len] = 0;
    +    return UTF8len + 1;
    +}
    +
     // Obtain a wide representation of the MLU, on depending on current locale settings
     cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
                                           const char LanguageCode[3], const char CountryCode[3],
    @@ -470,12 +674,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
         // Maybe we want only to know the len?
         if (Buffer == NULL) return StrLen + sizeof(wchar_t);
     
    -  // No buffer size means no data
    -    if (BufferSize <= 0) return 0;
    +    // Invalid buffer size means no data
    +    if (BufferSize < sizeof(wchar_t)) return 0;
     
         // Some clipping may be required
         if (BufferSize < StrLen + sizeof(wchar_t))
    -        StrLen = BufferSize - + sizeof(wchar_t);
    +        StrLen = BufferSize - sizeof(wchar_t);
     
         memmove(Buffer, Wide, StrLen);
         Buffer[StrLen / sizeof(wchar_t)] = 0;
    @@ -843,13 +1047,19 @@ void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
     {
         cmsUInt32Number i;
     
    -    for (i=0; i < pseq ->n; i++) {
    -        if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
    -        if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
    -        if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
    +    if (pseq == NULL)
    +        return;
    +
    +    if (pseq ->seq != NULL) {
    +        for (i=0; i < pseq ->n; i++) {
    +            if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
    +            if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
    +            if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
    +        }
    +
    +        _cmsFree(pseq ->ContextID, pseq ->seq);
         }
     
    -    if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
         _cmsFree(pseq -> ContextID, pseq);
     }
     
    diff --git a/src/java.desktop/share/native/liblcms/cmsopt.c b/src/java.desktop/share/native/liblcms/cmsopt.c
    index 3e81ae1df1ba0..421a4f4a70193 100644
    --- a/src/java.desktop/share/native/liblcms/cmsopt.c
    +++ b/src/java.desktop/share/native/liblcms/cmsopt.c
    @@ -212,6 +212,7 @@ cmsBool  isFloatMatrixIdentity(const cmsMAT3* a)
     
            return TRUE;
     }
    +
     // if two adjacent matrices are found, multiply them.
     static
     cmsBool _MultiplyMatrix(cmsPipeline* Lut)
    @@ -1142,14 +1143,17 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
     
             // Store result in curve
             for (t=0; t < OriginalLut ->InputChannels; t++)
    -            Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0);
    +        {
    +            if (Trans[t]->Table16 != NULL)
    +                Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0);
    +        }
         }
     
         // Slope-limit the obtained curves
         for (t = 0; t < OriginalLut ->InputChannels; t++)
             SlopeLimiting(Trans[t]);
     
    -    // Check for validity
    +    // Check for validity. lIsLinear is here for debug purposes
         lIsSuitable = TRUE;
         lIsLinear   = TRUE;
         for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) {
    @@ -1753,6 +1757,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
     
                          _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1);
     
    +                     if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3) return FALSE;
    +
                          // Copy the matrix to our result
                          memcpy(&res, Data->Double, sizeof(res));
     
    @@ -1797,7 +1803,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
             _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2);
     
             // In this particular optimization, cache does not help as it takes more time to deal with
    -        // the cache that with the pixel handling
    +        // the cache than with the pixel handling
             *dwFlags |= cmsFLAGS_NOCACHE;
     
             // Setup the optimizarion routines
    @@ -1954,7 +1960,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
         for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut);
             mpe != NULL;
             mpe = cmsStageNext(mpe)) {
    -        if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
    +            if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
         }
     
         // Try to get rid of identities and trivial conversions.
    diff --git a/src/java.desktop/share/native/liblcms/cmspack.c b/src/java.desktop/share/native/liblcms/cmspack.c
    index da5fc6019d384..fc875995a80c2 100644
    --- a/src/java.desktop/share/native/liblcms/cmspack.c
    +++ b/src/java.desktop/share/native/liblcms/cmspack.c
    @@ -2980,6 +2980,108 @@ cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info,
     
     // --------------------------------------------------------------------------------------------------------
     
    +static
    +cmsUInt8Number* PackBytesFromFloat(_cmsTRANSFORM* info,
    +                                    cmsFloat32Number wOut[],
    +                                    cmsUInt8Number* output,
    +                                    cmsUInt32Number Stride)
    +{
    +    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
    +    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
    +    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
    +    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
    +    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
    +    cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
    +    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
    +    cmsUInt8Number* swap1 = (cmsUInt8Number*)output;
    +    cmsFloat64Number v = 0;
    +    cmsUInt8Number vv = 0;
    +    cmsUInt32Number i, start = 0;
    +
    +    if (ExtraFirst)
    +        start = Extra;
    +
    +    for (i = 0; i < nChan; i++) {
    +
    +        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
    +
    +        v = wOut[index] * 65535.0;
    +
    +        if (Reverse)
    +            v = 65535.0 - v;
    +
    +        vv =  FROM_16_TO_8(_cmsQuickSaturateWord(v));
    +
    +        if (Planar)
    +            ((cmsUInt8Number*)output)[(i + start) * Stride] = vv;
    +        else
    +            ((cmsUInt8Number*)output)[i + start] = vv;
    +    }
    +
    +
    +    if (Extra == 0 && SwapFirst) {
    +
    +        memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number));
    +        *swap1 = vv;
    +    }
    +
    +    if (T_PLANAR(info->OutputFormat))
    +        return output + sizeof(cmsUInt8Number);
    +    else
    +        return output + (nChan + Extra) * sizeof(cmsUInt8Number);
    +}
    +
    +static
    +cmsUInt8Number* PackWordsFromFloat(_cmsTRANSFORM* info,
    +                                    cmsFloat32Number wOut[],
    +                                    cmsUInt8Number* output,
    +                                    cmsUInt32Number Stride)
    +{
    +    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
    +    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
    +    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
    +    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
    +    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
    +    cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
    +    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
    +    cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
    +    cmsFloat64Number v = 0;
    +    cmsUInt16Number vv = 0;
    +    cmsUInt32Number i, start = 0;
    +
    +    if (ExtraFirst)
    +        start = Extra;
    +
    +    for (i = 0; i < nChan; i++) {
    +
    +        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
    +
    +        v = wOut[index] * 65535.0;
    +
    +        if (Reverse)
    +            v = 65535.0 - v;
    +
    +        vv = _cmsQuickSaturateWord(v);
    +
    +        if (Planar)
    +            ((cmsUInt16Number*)output)[(i + start) * Stride] = vv;
    +        else
    +            ((cmsUInt16Number*)output)[i + start] = vv;
    +    }
    +
    +    if (Extra == 0 && SwapFirst) {
    +
    +        memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number));
    +        *swap1 = vv;
    +    }
    +
    +    if (T_PLANAR(info->OutputFormat))
    +        return output + sizeof(cmsUInt16Number);
    +    else
    +        return output + (nChan + Extra) * sizeof(cmsUInt16Number);
    +}
    +
    +
     static
     cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
                                         cmsFloat32Number wOut[],
    @@ -3143,6 +3245,77 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
     }
     
     
    +static
    +cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info,
    +                                           cmsFloat32Number wOut[],
    +                                           cmsUInt8Number* output,
    +                                           cmsUInt32Number Stride)
    +{
    +    cmsCIELab Lab;
    +    cmsUInt16Number wlab[3];
    +
    +    Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
    +    Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
    +    Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
    +
    +    cmsFloat2LabEncoded(wlab, &Lab);
    +
    +    if (T_PLANAR(Info -> OutputFormat)) {
    +
    +        Stride /= PixelSize(Info->OutputFormat);
    +
    +        output[0]        = wlab[0] >> 8;
    +        output[Stride]   = wlab[1] >> 8;
    +        output[Stride*2] = wlab[2] >> 8;
    +
    +        return output + 1;
    +    }
    +    else {
    +
    +        output[0] = wlab[0] >> 8;
    +        output[1] = wlab[1] >> 8;
    +        output[2] = wlab[2] >> 8;
    +
    +        return output + (3 + T_EXTRA(Info ->OutputFormat));
    +    }
    +}
    +
    +static
    +cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info,
    +                                           cmsFloat32Number wOut[],
    +                                           cmsUInt8Number* output,
    +                                           cmsUInt32Number Stride)
    +{
    +    cmsCIELab Lab;
    +    cmsUInt16Number wlab[3];
    +
    +    Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
    +    Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
    +    Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
    +
    +    cmsFloat2LabEncodedV2(wlab, &Lab);
    +
    +    if (T_PLANAR(Info -> OutputFormat)) {
    +
    +        Stride /= PixelSize(Info->OutputFormat);
    +
    +        ((cmsUInt16Number*) output)[0]        = wlab[0];
    +        ((cmsUInt16Number*) output)[Stride]   = wlab[1];
    +        ((cmsUInt16Number*) output)[Stride*2] = wlab[2];
    +
    +        return output + sizeof(cmsUInt16Number);
    +    }
    +    else {
    +
    +         ((cmsUInt16Number*) output)[0] = wlab[0];
    +         ((cmsUInt16Number*) output)[1] = wlab[1];
    +         ((cmsUInt16Number*) output)[2] = wlab[2];
    +
    +        return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number);
    +    }
    +}
    +
    +
     // From 0..1 range to 0..MAX_ENCODEABLE_XYZ
     static
     cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
    @@ -3676,10 +3849,20 @@ static const cmsFormattersFloat OutputFormattersFloat[] = {
         {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
         {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
     
    +    {     TYPE_LabV2_8,                                                ANYPLANAR|ANYEXTRA,   PackEncodedBytesLabV2FromFloat},
    +    {     TYPE_LabV2_16,                                               ANYPLANAR|ANYEXTRA,   PackEncodedWordsLabV2FromFloat},
    +
         {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
                                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
         {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
                                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
    +
    +    {     BYTES_SH(2), ANYPLANAR|
    +                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackWordsFromFloat },
    +
    +    {     BYTES_SH(1), ANYPLANAR|
    +                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackBytesFromFloat },
    +
     #ifndef CMS_NO_HALF_SUPPORT
         {     FLOAT_SH(1)|BYTES_SH(2),
                                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
    @@ -3890,7 +4073,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU
         cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
     
         cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
    -    cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
    +    cmsInt32Number  nOutputChans = cmsChannelsOfColorSpace(ColorSpace);
         cmsUInt32Number Float = lIsFloat ? 1U : 0;
     
         // Unsupported color space?
    diff --git a/src/java.desktop/share/native/liblcms/cmsplugin.c b/src/java.desktop/share/native/liblcms/cmsplugin.c
    index c2808bb9278e9..f84e0172c813d 100644
    --- a/src/java.desktop/share/native/liblcms/cmsplugin.c
    +++ b/src/java.desktop/share/native/liblcms/cmsplugin.c
    @@ -393,12 +393,7 @@ cmsBool CMSEXPORT  _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
     // from Fixed point 8.8 to double
     cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
     {
    -       cmsUInt8Number  msb, lsb;
    -
    -       lsb = (cmsUInt8Number) (fixed8 & 0xff);
    -       msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
    -
    -       return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
    +    return fixed8 / 256.0;
     }
     
     cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
    @@ -410,19 +405,7 @@ cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
     // from Fixed point 15.16 to double
     cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
     {
    -    cmsFloat64Number floater, sign, mid;
    -    int Whole, FracPart;
    -
    -    sign  = (fix32 < 0 ? -1 : 1);
    -    fix32 = abs(fix32);
    -
    -    Whole     = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
    -    FracPart  = (cmsUInt16Number)(fix32 & 0xffff);
    -
    -    mid     = (cmsFloat64Number) FracPart / 65536.0;
    -    floater = (cmsFloat64Number) Whole + mid;
    -
    -    return sign * floater;
    +    return fix32 / 65536.0;
     }
     
     // from double to Fixed point 15.16
    diff --git a/src/java.desktop/share/native/liblcms/cmsps2.c b/src/java.desktop/share/native/liblcms/cmsps2.c
    index 537f685406779..9a2ab464f315a 100644
    --- a/src/java.desktop/share/native/liblcms/cmsps2.c
    +++ b/src/java.desktop/share/native/liblcms/cmsps2.c
    @@ -460,48 +460,46 @@ void EmitLab2XYZ(cmsIOHANDLER* m)
         _cmsIOPrintf(m, "]\n");
     }
     
    -static
    -void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name)
    -{
    -    _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name);
    -    _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name);
    -}
     
    -static
    -void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth)
    -{
    -    _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name);
    -    if (depth > 1) {
    -        // cycle topmost items on the stack to bring the previous definition to the front
    -        _cmsIOPrintf(m, "%d -1 roll ", depth);
    -    }
    -    _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name);
    -}
     
     // Outputs a table of words. It does use 16 bits
     
     static
    -void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
    +void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
     {
         cmsUInt32Number i;
         cmsFloat64Number gamma;
     
    -    if (Table == NULL) return; // Error
    +    /**
    +    * On error, empty tables or lienar assume gamma 1.0
    +    */
    +    if (Table == NULL ||
    +        Table->nEntries <= 0 ||
    +        cmsIsToneCurveLinear(Table)) {
     
    -    if (Table ->nEntries <= 0) return;  // Empty table
    +        _cmsIOPrintf(m, "{ 1 } bind ");
    +        return;
    +    }
     
    -    // Suppress whole if identity
    -    if (cmsIsToneCurveLinear(Table)) return;
     
         // Check if is really an exponential. If so, emit "exp"
         gamma = cmsEstimateGamma(Table, 0.001);
          if (gamma > 0) {
    -            _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma);
    +            _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
                 return;
          }
     
    -    EmitSafeGuardBegin(m, "lcms2gammatable");
    -    _cmsIOPrintf(m, "/lcms2gammatable [");
    +    _cmsIOPrintf(m, "{ ");
    +
    +    // Bounds check
    +    EmitRangeCheck(m);
    +
    +    // Emit intepolation code
    +
    +    // PostScript code                      Stack
    +    // ===============                      ========================
    +                                            // v
    +    _cmsIOPrintf(m, " [");
     
         for (i=0; i < Table->nEntries; i++) {
         if (i % 10 == 0)
    @@ -509,20 +507,8 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
             _cmsIOPrintf(m, "%d ", Table->Table16[i]);
         }
     
    -    _cmsIOPrintf(m, "] def\n");
    +    _cmsIOPrintf(m, "] ");                        // v tab
     
    -
    -    // Emit interpolation code
    -
    -    // PostScript code                            Stack
    -    // ===============                            ========================
    -                                                  // v
    -    _cmsIOPrintf(m, "/%s {\n  ", name);
    -
    -    // Bounds check
    -    EmitRangeCheck(m);
    -
    -    _cmsIOPrintf(m, "\n  //lcms2gammatable ");    // v tab
         _cmsIOPrintf(m, "dup ");                      // v tab tab
         _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
         _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
    @@ -549,9 +535,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
         _cmsIOPrintf(m, "add ");                      // y
         _cmsIOPrintf(m, "65535 div\n");               // result
     
    -    _cmsIOPrintf(m, "} bind def\n");
    -
    -    EmitSafeGuardEnd(m, "lcms2gammatable", 1);
    +    _cmsIOPrintf(m, " } bind ");
     }
     
     
    @@ -568,10 +552,10 @@ cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Numb
     // Does write a set of gamma curves
     
     static
    -void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix)
    +void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[])
     {
         cmsUInt32Number i;
    -    static char buffer[2048];
    +
     
         for( i=0; i < n; i++ )
         {
    @@ -579,12 +563,10 @@ void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const cha
     
             if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) {
     
    -            _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1);
    +            _cmsIOPrintf(m, "dup ");
             }
             else {
    -            snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i);
    -        buffer[sizeof(buffer)-1] = '\0';
    -            Emit1Gamma(m, g[i], buffer);
    +            Emit1Gamma(m, g[i]);
             }
         }
     
    @@ -708,18 +690,21 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
         sc.FixWhite = FixWhite;
         sc.ColorSpace = ColorSpace;
     
    -    _cmsIOPrintf(m, "[");
    +    if (sc.Pipeline != NULL && sc.Pipeline->Params != NULL) {
     
    -    for (i=0; i < sc.Pipeline->Params->nInputs; i++)
    -        _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
    +        _cmsIOPrintf(m, "[");
     
    -    _cmsIOPrintf(m, " [\n");
    +        for (i = 0; i < sc.Pipeline->Params->nInputs; i++)
    +            _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
     
    -    cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
    +        _cmsIOPrintf(m, " [\n");
     
    -    _cmsIOPrintf(m, PostMin);
    -    _cmsIOPrintf(m, PostMaj);
    -    _cmsIOPrintf(m, "] ");
    +        cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*)&sc, SAMPLER_INSPECT);
    +
    +        _cmsIOPrintf(m, PostMin);
    +        _cmsIOPrintf(m, PostMaj);
    +        _cmsIOPrintf(m, "] ");
    +    }
     
     }
     
    @@ -733,11 +718,11 @@ int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
         _cmsIOPrintf(m, "[ /CIEBasedA\n");
         _cmsIOPrintf(m, "  <<\n");
     
    -    EmitSafeGuardBegin(m, "lcms2gammaproc");
    -    Emit1Gamma(m, Curve, "lcms2gammaproc");
    +    _cmsIOPrintf(m, "/DecodeA ");
    +
    +    Emit1Gamma(m, Curve);
     
    -    _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n");
    -    EmitSafeGuardEnd(m, "lcms2gammaproc", 3);
    +    _cmsIOPrintf(m, " \n");
     
         _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
         _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
    @@ -761,19 +746,11 @@ int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** Cu
     
         _cmsIOPrintf(m, "[ /CIEBasedABC\n");
         _cmsIOPrintf(m, "<<\n");
    +    _cmsIOPrintf(m, "/DecodeABC [ ");
    +
    +    EmitNGamma(m, 3, CurveSet);
     
    -    EmitSafeGuardBegin(m, "lcms2gammaproc0");
    -    EmitSafeGuardBegin(m, "lcms2gammaproc1");
    -    EmitSafeGuardBegin(m, "lcms2gammaproc2");
    -    EmitNGamma(m, 3, CurveSet, "lcms2gammaproc");
    -    _cmsIOPrintf(m, "/DecodeABC [\n");
    -    _cmsIOPrintf(m, "   /lcms2gammaproc0 load\n");
    -    _cmsIOPrintf(m, "   /lcms2gammaproc1 load\n");
    -    _cmsIOPrintf(m, "   /lcms2gammaproc2 load\n");
         _cmsIOPrintf(m, "]\n");
    -    EmitSafeGuardEnd(m, "lcms2gammaproc2", 3);
    -    EmitSafeGuardEnd(m, "lcms2gammaproc1", 3);
    -    EmitSafeGuardEnd(m, "lcms2gammaproc0", 3);
     
         _cmsIOPrintf(m, "/MatrixABC [ " );
     
    @@ -805,10 +782,8 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte
     {
         const char* PreMaj;
         const char* PostMaj;
    -    const char* PreMin, * PostMin;
    +    const char* PreMin, *PostMin;
         cmsStage* mpe;
    -    int i, numchans;
    -    static char buffer[2048];
     
         mpe = Pipeline->Elements;
     
    @@ -837,34 +812,18 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte
     
         if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
     
    -        numchans = (int) cmsStageOutputChannels(mpe);
    -        for (i = 0; i < numchans; ++i) {
    -            snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
    -            buffer[sizeof(buffer) - 1] = '\0';
    -            EmitSafeGuardBegin(m, buffer);
    -        }
    -        EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc");
    -        _cmsIOPrintf(m, "/DecodeDEF [\n");
    -        for (i = 0; i < numchans; ++i) {
    -            snprintf(buffer, sizeof(buffer), "  /lcms2gammaproc%d load\n", i);
    -            buffer[sizeof(buffer) - 1] = '\0';
    -            _cmsIOPrintf(m, buffer);
    -        }
    +        _cmsIOPrintf(m, "/DecodeDEF [ ");
    +        EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
             _cmsIOPrintf(m, "]\n");
    -        for (i = numchans - 1; i >= 0; --i) {
    -            snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
    -            buffer[sizeof(buffer) - 1] = '\0';
    -            EmitSafeGuardEnd(m, buffer, 3);
    -        }
     
    -        mpe = mpe->Next;
    +        mpe = mpe ->Next;
         }
     
         if (cmsStageType(mpe) == cmsSigCLutElemType) {
     
    -        _cmsIOPrintf(m, "/Table ");
    -        WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0);
    -        _cmsIOPrintf(m, "]\n");
    +            _cmsIOPrintf(m, "/Table ");
    +            WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
    +            _cmsIOPrintf(m, "]\n");
         }
     
         EmitLab2XYZ(m);
    @@ -1024,9 +983,9 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr
                     for (j = 0; j < 3; j++)
                         Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
     
    -            rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat,
    -                _cmsStageGetPtrToCurveSet(Shaper),
    -                &BlackPointAdaptedToD50);
    +            rc = EmitCIEBasedABC(m,  (cmsFloat64Number *) &Mat,
    +                                _cmsStageGetPtrToCurveSet(Shaper),
    +                                 &BlackPointAdaptedToD50);
             }
             else {
     
    @@ -1053,10 +1012,15 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
     
         hLab  = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
         xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);
    +    cmsCloseProfile(hLab);
    +
         if (xform == NULL) return 0;
     
         NamedColorList = cmsGetNamedColorList(xform);
    -    if (NamedColorList == NULL) return 0;
    +    if (NamedColorList == NULL) {
    +        cmsDeleteTransform(xform);
    +        return 0;
    +    }
     
         _cmsIOPrintf(m, "<<\n");
         _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
    @@ -1065,7 +1029,6 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
     
         nColors   = cmsNamedColorCount(NamedColorList);
     
    -
         for (i=0; i < nColors; i++) {
     
             cmsUInt16Number In[1];
    @@ -1080,12 +1043,9 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
             _cmsIOPrintf(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
         }
     
    -
    -
         _cmsIOPrintf(m, ">>\n");
     
         cmsDeleteTransform(xform);
    -    cmsCloseProfile(hLab);
         return 1;
     }
     
    @@ -1339,7 +1299,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
         cmsUInt32Number InFrm = TYPE_Lab_16;
         cmsUInt32Number RelativeEncodingIntent;
         cmsColorSpaceSignature ColorSpace;
    -
    +    cmsStage* first;
     
         hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
         if (hLab == NULL) return 0;
    @@ -1366,7 +1326,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
         cmsCloseProfile(hLab);
     
         if (xform == NULL) {
    -
             cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
             return 0;
         }
    @@ -1374,10 +1333,12 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
         // Get a copy of the internal devicelink
         v = (_cmsTRANSFORM*) xform;
         DeviceLink = cmsPipelineDup(v ->Lut);
    -    if (DeviceLink == NULL) return 0;
    -
    +    if (DeviceLink == NULL) {
    +        cmsDeleteTransform(xform);
    +        return 0;
    +    }
     
    -    // We need a CLUT
    +     // We need a CLUT
         dwFlags |= cmsFLAGS_FORCE_CLUT;
         _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
     
    @@ -1404,8 +1365,10 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
     
         _cmsIOPrintf(m, "/RenderTable ");
     
    -
    -    WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);
    +    first = cmsPipelineGetPtrToFirstStage(DeviceLink);
    +    if (first != NULL) {
    +        WriteCLUT(m, first, "<", ">\n", "", "", lFixWhite, ColorSpace);
    +    }
     
         _cmsIOPrintf(m, " %d {} bind ", nChannels);
     
    @@ -1414,7 +1377,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
     
         _cmsIOPrintf(m, "]\n");
     
    -
         EmitIntent(m, Intent);
     
         _cmsIOPrintf(m, ">>\n");
    @@ -1477,7 +1439,10 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
     
     
         NamedColorList = cmsGetNamedColorList(xform);
    -    if (NamedColorList == NULL) return 0;
    +    if (NamedColorList == NULL) {
    +        cmsDeleteTransform(xform);
    +        return 0;
    +    }
     
         _cmsIOPrintf(m, "<<\n");
         _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
    diff --git a/src/java.desktop/share/native/liblcms/cmssamp.c b/src/java.desktop/share/native/liblcms/cmssamp.c
    index 8a01f7ec6859b..74f5f4bff29b5 100644
    --- a/src/java.desktop/share/native/liblcms/cmssamp.c
    +++ b/src/java.desktop/share/native/liblcms/cmssamp.c
    @@ -152,7 +152,7 @@ cmsBool  BlackPointAsDarkerColorant(cmsHPROFILE    hInput,
         // Convert black to Lab
         cmsDoTransform(xform, Black, &Lab, 1);
     
    -    // Force it to be neutral, check for inconsistences
    +    // Force it to be neutral, check for inconsistencies
         Lab.a = Lab.b = 0;
         if (Lab.L > 50 || Lab.L < 0) Lab.L = 0;
     
    diff --git a/src/java.desktop/share/native/liblcms/cmstypes.c b/src/java.desktop/share/native/liblcms/cmstypes.c
    index 7b07b6b9cf436..862f393497aa4 100644
    --- a/src/java.desktop/share/native/liblcms/cmstypes.c
    +++ b/src/java.desktop/share/native/liblcms/cmstypes.c
    @@ -122,7 +122,7 @@ cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient
         return TRUE;
     }
     
    -// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
    +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additions
     // made by plug-ins and then the built-in defaults.
     static
     cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
    @@ -954,6 +954,7 @@ static
     void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
     {
         char* Text = NULL;
    +    wchar_t* UnicodeString = NULL;
         cmsMLU* mlu = NULL;
         cmsUInt32Number  AsciiCount;
         cmsUInt32Number  i, UnicodeCode, UnicodeCount;
    @@ -973,7 +974,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND
         if (SizeOfTag < AsciiCount) return NULL;
     
         // All seems Ok, allocate the container
    -    mlu = cmsMLUalloc(self ->ContextID, 1);
    +    mlu = cmsMLUalloc(self ->ContextID, 2);
         if (mlu == NULL) return NULL;
     
         // As many memory as size of tag
    @@ -998,15 +999,30 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND
         if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
         SizeOfTag -= 2* sizeof(cmsUInt32Number);
     
    -    if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
    +    if (UnicodeCount == 0 || SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
    +
    +    UnicodeString = (wchar_t*)_cmsMallocZero(self->ContextID, (UnicodeCount + 1) * sizeof(wchar_t));
    +    if (UnicodeString == NULL) goto Done;
    +
    +    if (!_cmsReadWCharArray(io, UnicodeCount, UnicodeString)) {
    +        _cmsFree(self->ContextID, (void*)UnicodeString);
    +        goto Done;
    +    }
    +
    +    UnicodeString[UnicodeCount] = 0;
     
    -    for (i=0; i < UnicodeCount; i++) {
    -        if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
    +    if (!cmsMLUsetWide(mlu, cmsV2Unicode, cmsV2Unicode, UnicodeString)) {
    +        _cmsFree(self->ContextID, (void*)UnicodeString);
    +        goto Done;
         }
    +
    +    _cmsFree(self->ContextID, (void*)UnicodeString);
    +    UnicodeString = NULL;
    +
         SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
     
         // Skip ScriptCode code if present. Some buggy profiles does have less
    -    // data that stricttly required. We need to skip it as this type may come
    +    // data that strictly required. We need to skip it as this type may come
         // embedded in other types.
     
         if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
    @@ -1026,6 +1042,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND
         return mlu;
     
     Error:
    +    if (UnicodeString)  _cmsFree(self->ContextID, (void*)UnicodeString);
         if (Text) _cmsFree(self ->ContextID, (void*) Text);
         if (mlu) cmsMLUfree(mlu);
         return NULL;
    @@ -1078,7 +1095,7 @@ cmsBool  Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO
     
             // Get both representations.
             cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry,  Text, len * sizeof(char));
    -        cmsMLUgetWide(mlu,  cmsNoLanguage, cmsNoCountry,  Wide, len * sizeof(wchar_t));
    +        cmsMLUgetWide(mlu,  cmsV2Unicode,  cmsV2Unicode,  Wide, len * sizeof(wchar_t));
         }
     
         // Tell the real text len including the null terminator and padding
    @@ -1577,8 +1594,6 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU
         if (SizeOfTag == 0)
         {
             Block = NULL;
    -        NumOfWchar = 0;
    -
         }
         else
         {
    @@ -1940,7 +1955,7 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
     
     // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
     static
    -cmsBool  Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
    +cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
     {
         cmsUInt32Number j, nTabSize, i;
         cmsUInt8Number  val;
    @@ -1953,6 +1968,12 @@ cmsBool  Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
     
         // Disassemble the LUT into components.
         mpe = NewLUT -> Elements;
    +
    +    if (mpe == NULL) {  // Should never be empty. Corrupted?
    +        cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "empty LUT8 is not supported");
    +        return FALSE;
    +    }
    +
         if (mpe ->Type == cmsSigMatrixElemType) {
     
             if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE;
    @@ -2694,8 +2715,8 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
             // If this is a table-based curve, use curve type even on V4
             CurrentType = Type;
     
    -        if ((Curves[i] ->nSegments == 0)||
    -            ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
    +        if ((Curves[i] ->nSegments == 0) ||                                         // 16 bits tabulated
    +            ((Curves[i]->nSegments == 3) && (Curves[i] ->Segments[1].Type == 0)) )  // Floating-point tabulated
                 CurrentType = cmsSigCurveType;
             else
             if (Curves[i] ->Segments[0].Type < 0)
    @@ -4459,8 +4480,8 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
         if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
         if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
     
    -    if (InputChans == 0) goto Error;
    -    if (OutputChans == 0) goto Error;
    +    if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) goto Error;
    +    if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) goto Error;
     
         if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
             goto Error;
    @@ -5250,11 +5271,13 @@ cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,  _c
         }
     
         Before = io ->Tell(io);
    -    e ->Offsets[i] = Before - BaseOffset;
    +    if (e->Offsets != NULL)
    +        e ->Offsets[i] = Before - BaseOffset;
     
         if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
     
    -    e ->Sizes[i] = io ->Tell(io) - Before;
    +    if (e->Sizes != NULL)
    +        e ->Sizes[i] = io ->Tell(io) - Before;
         return TRUE;
     }
     
    @@ -5499,6 +5522,216 @@ void Type_VideoSignal_Free(struct _cms_typehandler_struct* self, void* Ptr)
         _cmsFree(self->ContextID, Ptr);
     }
     
    +
    +// ********************************************************************************
    +// Microsoft's MHC2 Type support
    +// ********************************************************************************
    +
    +static
    +void SetIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4])
    +{
    +    XYZ2XYZmatrix[0][0] = 1.0; XYZ2XYZmatrix[0][1] = 0.0; XYZ2XYZmatrix[0][2] = 0.0; XYZ2XYZmatrix[0][3] = 0.0;
    +    XYZ2XYZmatrix[1][0] = 0.0; XYZ2XYZmatrix[1][1] = 1.0; XYZ2XYZmatrix[1][2] = 0.0; XYZ2XYZmatrix[1][3] = 0.0;
    +    XYZ2XYZmatrix[2][0] = 0.0; XYZ2XYZmatrix[2][1] = 0.0; XYZ2XYZmatrix[2][2] = 1.0; XYZ2XYZmatrix[2][3] = 0.0;
    +}
    +
    +static
    +cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
    +{
    +    return fabs(b - a) < (1.0 / 65535.0);
    +}
    +
    +cmsBool IsIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4])
    +{
    +    cmsFloat64Number Identity[3][4];
    +    int i, j;
    +
    +    SetIdentity(Identity);
    +
    +    for (i = 0; i < 3; i++)
    +        for (j = 0; j < 4; j++)
    +            if (!CloseEnough(XYZ2XYZmatrix[i][j], Identity[i][j])) return FALSE;
    +
    +    return TRUE;
    +}
    +
    +static
    +void Type_MHC2_Free(struct _cms_typehandler_struct* self, void* Ptr)
    +{
    +    cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr;
    +
    +    if (mhc2->RedCurve != NULL) _cmsFree(self->ContextID, mhc2->RedCurve);
    +    if (mhc2->GreenCurve != NULL) _cmsFree(self->ContextID, mhc2->GreenCurve);
    +    if (mhc2->BlueCurve != NULL) _cmsFree(self->ContextID, mhc2->BlueCurve);
    +
    +    _cmsFree(self->ContextID, Ptr);
    +}
    +
    +void* Type_MHC2_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
    +{
    +    cmsMHC2Type* mhc2 = _cmsDupMem(self->ContextID, Ptr, sizeof(cmsMHC2Type));
    +
    +    mhc2->RedCurve = _cmsDupMem(self->ContextID,   mhc2->RedCurve, mhc2->CurveEntries*sizeof(cmsFloat64Number));
    +    mhc2->GreenCurve = _cmsDupMem(self->ContextID, mhc2->GreenCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
    +    mhc2->BlueCurve = _cmsDupMem(self->ContextID,  mhc2->BlueCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
    +
    +    if (mhc2->RedCurve == NULL ||
    +        mhc2->GreenCurve == NULL ||
    +        mhc2->BlueCurve == NULL) {
    +
    +        Type_MHC2_Free(self, mhc2);
    +        return NULL;
    +    }
    +
    +    return mhc2;
    +
    +    cmsUNUSED_PARAMETER(n);
    +}
    +
    +
    +static
    +cmsBool WriteDoubles(cmsIOHANDLER* io, cmsUInt32Number n, cmsFloat64Number* Values)
    +{
    +    cmsUInt32Number i;
    +
    +    for (i = 0; i < n; i++) {
    +
    +        if (!_cmsWrite15Fixed16Number(io, *Values++)) return FALSE;
    +    }
    +
    +    return TRUE;
    +}
    +
    +static
    +cmsBool Type_MHC2_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
    +{
    +    cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr;
    +    cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase);
    +    cmsUInt32Number TablesOffsetPos;
    +    cmsUInt32Number MatrixOffset;
    +    cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable;
    +
    +    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
    +    if (!_cmsWriteUInt32Number(io, mhc2->CurveEntries)) return FALSE;
    +
    +    if (!_cmsWrite15Fixed16Number(io, mhc2->MinLuminance)) return FALSE;
    +    if (!_cmsWrite15Fixed16Number(io, mhc2->PeakLuminance)) return FALSE;
    +
    +    TablesOffsetPos = io->Tell(io);
    +
    +    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Matrix
    +    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Curve R
    +    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Curve G
    +    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Curve B
    +
    +
    +    if (IsIdentity(mhc2->XYZ2XYZmatrix))
    +    {
    +        MatrixOffset = 0;
    +    }
    +    else
    +    {
    +        MatrixOffset = io->Tell(io) - BaseOffset;
    +        if (!WriteDoubles(io, 3 * 4, &mhc2->XYZ2XYZmatrix[0][0])) return FALSE;
    +    }
    +
    +    OffsetRedTable = io->Tell(io) - BaseOffset;
    +    if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->RedCurve)) return FALSE;
    +    OffsetGreenTable = io->Tell(io) - BaseOffset;
    +    if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->GreenCurve)) return FALSE;
    +    OffsetBlueTable = io->Tell(io) - BaseOffset;
    +    if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->BlueCurve)) return FALSE;
    +
    +    if (!io->Seek(io, TablesOffsetPos)) return FALSE;
    +
    +    if (!_cmsWriteUInt32Number(io, MatrixOffset)) return FALSE;
    +    if (!_cmsWriteUInt32Number(io, OffsetRedTable)) return FALSE;
    +    if (!_cmsWriteUInt32Number(io, OffsetGreenTable)) return FALSE;
    +    if (!_cmsWriteUInt32Number(io, OffsetBlueTable)) return FALSE;
    +
    +    return TRUE;
    +
    +    cmsUNUSED_PARAMETER(self);
    +    cmsUNUSED_PARAMETER(nItems);
    +}
    +
    +
    +static
    +cmsBool ReadDoublesAt(cmsIOHANDLER* io, cmsUInt32Number At, cmsUInt32Number n, cmsFloat64Number* Values)
    +{
    +    cmsUInt32Number CurrentPos = io->Tell(io);
    +    cmsUInt32Number i;
    +
    +    if (!io->Seek(io, At)) return FALSE;
    +
    +    for (i = 0; i < n; i++) {
    +
    +        if (!_cmsRead15Fixed16Number(io, Values++)) return FALSE;
    +    }
    +
    +    if (!io->Seek(io, CurrentPos)) return FALSE;
    +
    +    return TRUE;
    +}
    +
    +static
    +void* Type_MHC2_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
    +{
    +    cmsMHC2Type* mhc2 = NULL;
    +
    +    cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase);
    +    cmsUInt32Number MatrixOffset;
    +    cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable;
    +
    +    if (!_cmsReadUInt32Number(io, NULL)) return NULL;
    +
    +    mhc2 = (cmsMHC2Type*)_cmsCalloc(self->ContextID, 1, sizeof(cmsMHC2Type));
    +    if (mhc2 == NULL) return NULL;
    +
    +    if (!_cmsReadUInt32Number(io,    &mhc2->CurveEntries)) goto Error;
    +
    +    if (mhc2->CurveEntries > 4096) goto Error;
    +
    +    mhc2->RedCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number));
    +    mhc2->GreenCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number));
    +    mhc2->BlueCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number));
    +
    +    if (mhc2->RedCurve == NULL ||
    +        mhc2->GreenCurve == NULL ||
    +        mhc2->BlueCurve == NULL)  goto Error;
    +
    +    if (!_cmsRead15Fixed16Number(io, &mhc2->MinLuminance)) goto Error;
    +    if (!_cmsRead15Fixed16Number(io, &mhc2->PeakLuminance)) goto Error;
    +
    +    if (!_cmsReadUInt32Number(io, &MatrixOffset)) goto Error;
    +    if (!_cmsReadUInt32Number(io, &OffsetRedTable)) goto Error;
    +    if (!_cmsReadUInt32Number(io, &OffsetGreenTable)) goto Error;
    +    if (!_cmsReadUInt32Number(io, &OffsetBlueTable)) goto Error;
    +
    +    if (MatrixOffset == 0)
    +        SetIdentity(mhc2->XYZ2XYZmatrix);
    +    else
    +    {
    +        if (!ReadDoublesAt(io, BaseOffset + MatrixOffset, 3*4, &mhc2->XYZ2XYZmatrix[0][0])) goto Error;
    +    }
    +
    +    if (!ReadDoublesAt(io, BaseOffset + OffsetRedTable, mhc2->CurveEntries, mhc2->RedCurve)) goto Error;
    +    if (!ReadDoublesAt(io, BaseOffset + OffsetGreenTable, mhc2->CurveEntries, mhc2->GreenCurve)) goto Error;
    +    if (!ReadDoublesAt(io, BaseOffset + OffsetBlueTable, mhc2->CurveEntries, mhc2->BlueCurve)) goto Error;
    +
    +    // Success
    +    *nItems = 1;
    +    return mhc2;
    +
    +Error:
    +    Type_MHC2_Free(self, mhc2);
    +    return NULL;
    +
    +    cmsUNUSED_PARAMETER(SizeOfTag);
    +}
    +
    +
    +
     // ********************************************************************************
     // Type support main routines
     // ********************************************************************************
    @@ -5538,7 +5771,8 @@ static const _cmsTagTypeLinkedList SupportedTagTypes[] = {
     {TYPE_HANDLER(cmsSigProfileSequenceIdType,     ProfileSequenceId),  (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] },
     {TYPE_HANDLER(cmsSigDictType,                  Dictionary),         (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] },
     {TYPE_HANDLER(cmsSigcicpType,                  VideoSignal),        (_cmsTagTypeLinkedList*) &SupportedTagTypes[31] },
    -{TYPE_HANDLER(cmsSigVcgtType,                  vcgt),                NULL }
    +{TYPE_HANDLER(cmsSigVcgtType,                  vcgt),               (_cmsTagTypeLinkedList*) &SupportedTagTypes[32] },
    +{TYPE_HANDLER(cmsSigMHC2Type,                  MHC2),                NULL }
     };
     
     
    @@ -5734,7 +5968,8 @@ static _cmsTagLinkedList SupportedTags[] = {
         { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
         { cmsSigcicpTag,                { 1, 1, { cmsSigcicpType},               NULL },   &SupportedTags[64]},
     
    -    { cmsSigArgyllArtsTag,          { 9, 1, { cmsSigS15Fixed16ArrayType},    NULL}, NULL}
    +    { cmsSigArgyllArtsTag,          { 9, 1, { cmsSigS15Fixed16ArrayType},    NULL}, &SupportedTags[65]},
    +    { cmsSigMHC2Tag,                { 1, 1, { cmsSigMHC2Type },              NULL}, NULL}
     
     };
     
    diff --git a/src/java.desktop/share/native/liblcms/cmsvirt.c b/src/java.desktop/share/native/liblcms/cmsvirt.c
    index 6ce0479617438..e8d18d4ca9f95 100644
    --- a/src/java.desktop/share/native/liblcms/cmsvirt.c
    +++ b/src/java.desktop/share/native/liblcms/cmsvirt.c
    @@ -435,10 +435,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
     
         if (Limit < 0.0 || Limit > 400) {
     
    -        cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400");
    -        if (Limit < 0) Limit = 0;
    +        cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 1..400");
    +        if (Limit < 1) Limit = 1;
             if (Limit > 400) Limit = 400;
    -
         }
     
         hICC = cmsCreateProfilePlaceholder(ContextID);
    @@ -701,6 +700,127 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void)
         return cmsCreate_sRGBProfileTHR(NULL);
     }
     
    +/**
    +* Oklab colorspace profile (experimental)
    +*
    +* This virtual profile cannot be saved as an ICC file
    +*/
    +cmsHPROFILE cmsCreate_OkLabProfile(cmsContext ctx)
    +{
    +    cmsStage* XYZPCS = _cmsStageNormalizeFromXyzFloat(ctx);
    +    cmsStage* PCSXYZ = _cmsStageNormalizeToXyzFloat(ctx);
    +
    +    const double M_D65_D50[] =
    +    {
    +       1.047886, 0.022919, -0.050216,
    +       0.029582, 0.990484, -0.017079,
    +      -0.009252, 0.015073,  0.751678
    +    };
    +
    +    const double M_D50_D65[] =
    +    {
    +         0.955512609517083, -0.023073214184645,  0.063308961782107,
    +        -0.028324949364887,  1.009942432477107,  0.021054814890112,
    +         0.012328875695483, -0.020535835374141,  1.330713916450354
    +    };
    +
    +    cmsStage* D65toD50 = cmsStageAllocMatrix(ctx, 3, 3, M_D65_D50, NULL);
    +    cmsStage* D50toD65 = cmsStageAllocMatrix(ctx, 3, 3, M_D50_D65, NULL);
    +
    +    const double M_D65_LMS[] =
    +    {
    +        0.8189330101, 0.3618667424, -0.1288597137,
    +        0.0329845436, 0.9293118715,  0.0361456387,
    +        0.0482003018, 0.2643662691,  0.6338517070
    +    };
    +
    +    const double M_LMS_D65[] =
    +    {
    +        1.227013851103521, -0.557799980651822,  0.281256148966468,
    +       -0.040580178423281,  1.112256869616830, -0.071676678665601,
    +       -0.076381284505707, -0.421481978418013,  1.586163220440795
    +    };
    +
    +    cmsStage* D65toLMS = cmsStageAllocMatrix(ctx, 3, 3, M_D65_LMS, NULL);
    +    cmsStage* LMStoD65 = cmsStageAllocMatrix(ctx, 3, 3, M_LMS_D65, NULL);
    +
    +    cmsToneCurve* CubeRoot = cmsBuildGamma(ctx, 1.0 / 3.0);
    +    cmsToneCurve* Cube     = cmsBuildGamma(ctx,  3.0);
    +
    +    cmsToneCurve* Roots[3] = { CubeRoot, CubeRoot, CubeRoot };
    +    cmsToneCurve* Cubes[3] = { Cube, Cube, Cube };
    +
    +    cmsStage* NonLinearityFw = cmsStageAllocToneCurves(ctx, 3, Roots);
    +    cmsStage* NonLinearityRv = cmsStageAllocToneCurves(ctx, 3, Cubes);
    +
    +    const double M_LMSprime_OkLab[] =
    +    {
    +        0.2104542553,  0.7936177850, -0.0040720468,
    +        1.9779984951, -2.4285922050,  0.4505937099,
    +        0.0259040371,  0.7827717662, -0.8086757660
    +    };
    +
    +    const double M_OkLab_LMSprime[] =
    +    {
    +        0.999999998450520,  0.396337792173768,  0.215803758060759,
    +        1.000000008881761, -0.105561342323656, -0.063854174771706,
    +        1.000000054672411, -0.089484182094966, -1.291485537864092
    +    };
    +
    +    cmsStage* LMSprime_OkLab = cmsStageAllocMatrix(ctx, 3, 3, M_LMSprime_OkLab, NULL);
    +    cmsStage* OkLab_LMSprime = cmsStageAllocMatrix(ctx, 3, 3, M_OkLab_LMSprime, NULL);
    +
    +    cmsPipeline* AToB = cmsPipelineAlloc(ctx, 3, 3);
    +    cmsPipeline* BToA = cmsPipelineAlloc(ctx, 3, 3);
    +
    +    cmsHPROFILE hProfile = cmsCreateProfilePlaceholder(ctx);
    +
    +    cmsSetProfileVersion(hProfile, 4.4);
    +
    +    cmsSetDeviceClass(hProfile, cmsSigColorSpaceClass);
    +    cmsSetColorSpace(hProfile, cmsSig3colorData);
    +    cmsSetPCS(hProfile, cmsSigXYZData);
    +
    +    cmsSetHeaderRenderingIntent(hProfile, INTENT_RELATIVE_COLORIMETRIC);
    +
    +    /**
    +    * Conversion PCS (XYZ/D50) to OkLab
    +    */
    +    if (!cmsPipelineInsertStage(BToA, cmsAT_END, PCSXYZ)) goto error;
    +    if (!cmsPipelineInsertStage(BToA, cmsAT_END, D50toD65)) goto error;
    +    if (!cmsPipelineInsertStage(BToA, cmsAT_END, D65toLMS)) goto error;
    +    if (!cmsPipelineInsertStage(BToA, cmsAT_END, NonLinearityFw)) goto error;
    +    if (!cmsPipelineInsertStage(BToA, cmsAT_END, LMSprime_OkLab)) goto error;
    +
    +    if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA)) goto error;
    +
    +    if (!cmsPipelineInsertStage(AToB, cmsAT_END, OkLab_LMSprime)) goto error;
    +    if (!cmsPipelineInsertStage(AToB, cmsAT_END, NonLinearityRv)) goto error;
    +    if (!cmsPipelineInsertStage(AToB, cmsAT_END, LMStoD65)) goto error;
    +    if (!cmsPipelineInsertStage(AToB, cmsAT_END, D65toD50)) goto error;
    +    if (!cmsPipelineInsertStage(AToB, cmsAT_END, XYZPCS)) goto error;
    +
    +    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB)) goto error;
    +
    +    cmsPipelineFree(BToA);
    +    cmsPipelineFree(AToB);
    +
    +    cmsFreeToneCurve(CubeRoot);
    +    cmsFreeToneCurve(Cube);
    +
    +    return hProfile;
    +
    +error:
    +    cmsPipelineFree(BToA);
    +    cmsPipelineFree(AToB);
    +
    +    cmsFreeToneCurve(CubeRoot);
    +    cmsFreeToneCurve(Cube);
    +    cmsCloseProfile(hProfile);
    +
    +    return NULL;
    +
    +}
     
     
     typedef struct {
    @@ -1060,7 +1180,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
     
         for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) {
     
    -        if (n > Tab ->nTypes) return FALSE;
    +        if (n >= Tab ->nTypes) return FALSE;
             if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE;
         }
     
    @@ -1091,9 +1211,9 @@ const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTa
     cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
     {
         cmsHPROFILE hProfile = NULL;
    -        cmsUInt32Number FrmIn, FrmOut;
    -        cmsInt32Number ChansIn, ChansOut;
    -        int ColorSpaceBitsIn, ColorSpaceBitsOut;
    +    cmsUInt32Number FrmIn, FrmOut;
    +    cmsInt32Number ChansIn, ChansOut;
    +    int ColorSpaceBitsIn, ColorSpaceBitsOut;
         _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
         cmsPipeline* LUT = NULL;
         cmsStage* mpe;
    @@ -1104,6 +1224,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
     
         _cmsAssert(hTransform != NULL);
     
    +    // Check if the pipeline holding is valid
    +    if (xform -> Lut == NULL) return NULL;
    +
         // Get the first mpe to check for named color
         mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);
     
    diff --git a/src/java.desktop/share/native/liblcms/cmsxform.c b/src/java.desktop/share/native/liblcms/cmsxform.c
    index 3f3ad28c6c486..86afd7202fdbf 100644
    --- a/src/java.desktop/share/native/liblcms/cmsxform.c
    +++ b/src/java.desktop/share/native/liblcms/cmsxform.c
    @@ -943,7 +943,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
            }
     
         // Check whatever this is a true floating point transform
    -    if (_cmsFormatterIsFloat(*OutputFormat)) {
    +    if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) {
     
             // Get formatter function always return a valid union, but the contents of this union may be NULL.
             p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
    @@ -1018,6 +1018,19 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
             }
         }
     
    +    /**
    +    * Check consistency for alpha channel copy
    +    */
    +    if (*dwFlags & cmsFLAGS_COPY_ALPHA)
    +    {
    +        if (T_EXTRA(*InputFormat) != T_EXTRA(*OutputFormat))
    +        {
    +            cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Mismatched alpha channels");
    +            cmsDeleteTransform(p);
    +            return NULL;
    +        }
    +    }
    +
         p ->InputFormat     = *InputFormat;
         p ->OutputFormat    = *OutputFormat;
         p ->dwOriginalFlags = *dwFlags;
    diff --git a/src/java.desktop/share/native/liblcms/lcms2.h b/src/java.desktop/share/native/liblcms/lcms2.h
    index d5b8c477f2388..2d9a8b1248f93 100644
    --- a/src/java.desktop/share/native/liblcms/lcms2.h
    +++ b/src/java.desktop/share/native/liblcms/lcms2.h
    @@ -52,7 +52,7 @@
     //
     //---------------------------------------------------------------------------------
     //
    -// Version 2.15
    +// Version 2.16
     //
     
     #ifndef _lcms2_H
    @@ -105,12 +105,15 @@
     
     #ifndef CMS_USE_CPP_API
     #   ifdef __cplusplus
    +#       if __cplusplus >= 201703L
    +#            define CMS_NO_REGISTER_KEYWORD 1
    +#       endif
     extern "C" {
     #   endif
     #endif
     
     // Version/release
    -#define LCMS_VERSION        2150
    +#define LCMS_VERSION        2160
     
     // I will give the chance of redefining basic types for compilers that are not fully C99 compliant
     #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
    @@ -354,7 +357,8 @@ typedef enum {
         cmsSigUInt8ArrayType                    = 0x75693038,  // 'ui08'
         cmsSigVcgtType                          = 0x76636774,  // 'vcgt'
         cmsSigViewingConditionsType             = 0x76696577,  // 'view'
    -    cmsSigXYZType                           = 0x58595A20   // 'XYZ '
    +    cmsSigXYZType                           = 0x58595A20,  // 'XYZ '
    +    cmsSigMHC2Type                          = 0x4D484332   // 'MHC2'
     
     
     } cmsTagTypeSignature;
    @@ -432,7 +436,8 @@ typedef enum {
         cmsSigVcgtTag                           = 0x76636774,  // 'vcgt'
         cmsSigMetaTag                           = 0x6D657461,  // 'meta'
         cmsSigcicpTag                           = 0x63696370,  // 'cicp'
    -    cmsSigArgyllArtsTag                     = 0x61727473   // 'arts'
    +    cmsSigArgyllArtsTag                     = 0x61727473,  // 'arts'
    +    cmsSigMHC2Tag                           = 0x4D484332   // 'MHC2'
     
     } cmsTagSignature;
     
    @@ -977,6 +982,7 @@ typedef void* cmsHTRANSFORM;
     #define TYPE_RGB_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
     #define TYPE_BGR_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1))
     #define TYPE_CMYK_DBL         (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0))
    +#define TYPE_OKLAB_DBL        (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|CHANNELS_SH(3)|BYTES_SH(0))
     
     // IEEE 754-2008 "half"
     #define TYPE_GRAY_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2))
    @@ -1077,6 +1083,19 @@ typedef struct {
     
     } cmsVideoSignalType;
     
    +typedef struct {
    +    cmsUInt32Number   CurveEntries;
    +    cmsFloat64Number* RedCurve;
    +    cmsFloat64Number* GreenCurve;
    +    cmsFloat64Number* BlueCurve;
    +
    +    cmsFloat64Number  MinLuminance;         // ST.2086 min luminance in nits
    +    cmsFloat64Number  PeakLuminance;        // ST.2086 peak luminance in nits
    +
    +    cmsFloat64Number XYZ2XYZmatrix[3][4];
    +
    +} cmsMHC2Type;
    +
     
     
     // Get LittleCMS version (for shared objects) -----------------------------------------------------------------------------
    @@ -1249,7 +1268,8 @@ CMSAPI cmsBool           CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t
     CMSAPI cmsBool           CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t);
     CMSAPI cmsInt32Number    CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t);
     CMSAPI cmsFloat64Number  CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision);
    -CMSAPI cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t);
    +
    +CMSAPI const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t);
     
     // Tone curve tabular estimation
     CMSAPI cmsUInt32Number         CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t);
    @@ -1343,8 +1363,11 @@ CMSAPI cmsBool           CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, c
     
     typedef struct _cms_MLU_struct cmsMLU;
     
    -#define  cmsNoLanguage "\0\0"
    -#define  cmsNoCountry  "\0\0"
    +#define  cmsNoLanguage    "\0\0"
    +#define  cmsNoCountry     "\0\0"
    +
    +// Special language/country to retrieve unicode field for description in V2 profiles. Use with care.
    +#define  cmsV2Unicode     "\xff\xff"
     
     CMSAPI cmsMLU*           CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems);
     CMSAPI void              CMSEXPORT cmsMLUfree(cmsMLU* mlu);
    @@ -1356,6 +1379,9 @@ CMSAPI cmsBool           CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu,
     CMSAPI cmsBool           CMSEXPORT cmsMLUsetWide(cmsMLU* mlu,
                                                       const char LanguageCode[3], const char CountryCode[3],
                                                       const wchar_t* WideString);
    +CMSAPI cmsBool           CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu,
    +                                                  const char LanguageCode[3], const char CountryCode[3],
    +                                                  const char* UTF8String);
     
     CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
                                                       const char LanguageCode[3], const char CountryCode[3],
    @@ -1364,6 +1390,10 @@ CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
     CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
                                                      const char LanguageCode[3], const char CountryCode[3],
                                                      wchar_t* Buffer, cmsUInt32Number BufferSize);
    +CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu,
    +                                                 const char LanguageCode[3], const char CountryCode[3],
    +                                                 char* Buffer, cmsUInt32Number BufferSize);
    +
     
     CMSAPI cmsBool           CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
                                                              const char LanguageCode[3], const char CountryCode[3],
    @@ -1588,6 +1618,10 @@ CMSAPI cmsUInt32Number   CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile,
                                                                 const char LanguageCode[3], const char CountryCode[3],
                                                                 char* Buffer, cmsUInt32Number BufferSize);
     
    +CMSAPI cmsUInt32Number  CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info,
    +                                                            const char LanguageCode[3], const char CountryCode[3],
    +                                                            char* Buffer, cmsUInt32Number BufferSize);
    +
     // IO handlers ----------------------------------------------------------------------------------------------------------
     
     typedef struct _cms_io_handler cmsIOHANDLER;
    @@ -1650,6 +1684,9 @@ CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext C
     
     CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit);
     
    +CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName);
    +
    +CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName);
     
     CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint);
     CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint);
    @@ -1662,6 +1699,8 @@ CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateXYZProfile(void);
     CMSAPI cmsHPROFILE      CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID);
     CMSAPI cmsHPROFILE      CMSEXPORT cmsCreate_sRGBProfile(void);
     
    +CMSAPI cmsHPROFILE      CMSEXPORT cmsCreate_OkLabProfile(cmsContext ctx);
    +
     CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
                                                                  cmsUInt32Number nLUTPoints,
                                                                  cmsFloat64Number Bright,
    diff --git a/src/java.desktop/share/native/liblcms/lcms2_internal.h b/src/java.desktop/share/native/liblcms/lcms2_internal.h
    index 4c29a6c021814..75973edad0d2c 100644
    --- a/src/java.desktop/share/native/liblcms/lcms2_internal.h
    +++ b/src/java.desktop/share/native/liblcms/lcms2_internal.h
    @@ -288,6 +288,7 @@ typedef CRITICAL_SECTION _cmsMutex;
     #ifdef _MSC_VER
     #    if (_MSC_VER >= 1800)
     #          pragma warning(disable : 26135)
    +#          pragma warning(disable : 4127)
     #    endif
     #endif
     
    @@ -545,7 +546,7 @@ struct _cmsContext_struct {
         struct _cmsContext_struct* Next;  // Points to next context in the new style
         _cmsSubAllocator* MemPool;        // The memory pool that stores context data
     
    -    void* chunks[MemoryClientMax];    // array of pointers to client chunks. Memory itself is hold in the suballocator.
    +    void* chunks[MemoryClientMax];    // array of pointers to client chunks. Memory itself is held in the suballocator.
                                           // If NULL, then it reverts to global Context0
     
         _cmsMemPluginChunkType DefaultMemoryManager;  // The allocators used for creating the context itself. Cannot be overridden
    @@ -839,6 +840,9 @@ typedef struct _cms_iccprofile_struct {
         // Creation time
         struct tm                Created;
     
    +    // Color management module identification
    +    cmsUInt32Number          CMM;
    +
         // Only most important items found in ICC profiles
         cmsUInt32Number          Version;
         cmsProfileClassSignature DeviceClass;
    @@ -846,6 +850,7 @@ typedef struct _cms_iccprofile_struct {
         cmsColorSpaceSignature   PCS;
         cmsUInt32Number          RenderingIntent;
     
    +    cmsPlatformSignature     platform;
         cmsUInt32Number          flags;
         cmsUInt32Number          manufacturer, model;
         cmsUInt64Number          attributes;
    diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java
    index c730140c01cdd..f28346292a6ce 100644
    --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java
    +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java
    @@ -1344,7 +1344,7 @@ protected void initComponentDefaults(UIDefaults table)
                                   "KP_DOWN", "selectNextRow",
                                "shift DOWN", "selectNextRowExtendSelection",
                             "shift KP_DOWN", "selectNextRowExtendSelection",
    -                      "ctrl shift DOWN", "selectNextRowExtendSelection",
    +                      "ctrl shift DOWN", "selectLastRowExtendSelection",
                        "ctrl shift KP_DOWN", "selectNextRowExtendSelection",
                                 "ctrl DOWN", "selectNextRowChangeLead",
                              "ctrl KP_DOWN", "selectNextRowChangeLead",
    @@ -1352,7 +1352,7 @@ protected void initComponentDefaults(UIDefaults table)
                                     "KP_UP", "selectPreviousRow",
                                  "shift UP", "selectPreviousRowExtendSelection",
                               "shift KP_UP", "selectPreviousRowExtendSelection",
    -                        "ctrl shift UP", "selectPreviousRowExtendSelection",
    +                        "ctrl shift UP", "selectFirstRowExtendSelection",
                          "ctrl shift KP_UP", "selectPreviousRowExtendSelection",
                                   "ctrl UP", "selectPreviousRowChangeLead",
                                "ctrl KP_UP", "selectPreviousRowChangeLead",
    diff --git a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
    index 12c2677e32a37..fad778dac4e0f 100644
    --- a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
    +++ b/src/java.desktop/windows/native/libawt/windows/ThemeReader.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
    @@ -492,7 +492,7 @@ static void rescale(SIZE *size) {
         }
     }
     
    -jobject newInsets(JNIEnv *env, jint top, jint left, jint bottom, jint right) {
    +static jobject newInsets(JNIEnv *env, jint top, jint left, jint bottom, jint right) {
         if (env->EnsureLocalCapacity(2) < 0) {
             return NULL;
         }
    diff --git a/src/java.desktop/windows/native/libawt/windows/awt_List.cpp b/src/java.desktop/windows/native/libawt/windows/awt_List.cpp
    index a04f6182a5b5f..7ffbb5c6a852d 100644
    --- a/src/java.desktop/windows/native/libawt/windows/awt_List.cpp
    +++ b/src/java.desktop/windows/native/libawt/windows/awt_List.cpp
    @@ -170,17 +170,6 @@ void AwtList::ReleaseDragCapture(UINT flags)
     void AwtList::Reshape(int x, int y, int w, int h)
     {
         AwtComponent::Reshape(x, y, w, h);
    -
    -/*
    -    HWND hList = GetListHandle();
    -    if (hList != NULL) {
    -        long flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS;
    -        /*
    -         * Fix for bug 4046446.
    -         * /
    -        SetWindowPos(hList, 0, 0, 0, w, h, flags);
    -    }
    -*/
     }
     
     //Netscape : Override the AwtComponent method so we can set the item height
    diff --git a/src/java.management/share/classes/com/sun/jmx/defaults/JmxProperties.java b/src/java.management/share/classes/com/sun/jmx/defaults/JmxProperties.java
    index 566d0f9d5cd68..a70080161afc3 100644
    --- a/src/java.management/share/classes/com/sun/jmx/defaults/JmxProperties.java
    +++ b/src/java.management/share/classes/com/sun/jmx/defaults/JmxProperties.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1999, 2017, 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
    @@ -44,24 +44,14 @@ private JmxProperties() {
         //------------------------
     
         /**
    -     * References the property that specifies the directory where
    -     * the native libraries will be stored before the MLet Service
    -     * loads them into memory.
    +     * References the property that optionally specifies the class name
    +     * of an alternative MBeanServerBuilder.
          * 

    - * Property Name: jmx.mlet.library.dir + * Property Name: javax.management.builder.initial */ public static final String JMX_INITIAL_BUILDER = "javax.management.builder.initial"; - /** - * References the property that specifies the directory where - * the native libraries will be stored before the MLet Service - * loads them into memory. - *

    - * Property Name: jmx.mlet.library.dir - */ - public static final String MLET_LIB_DIR = "jmx.mlet.library.dir"; - /** * References the property that specifies the full name of the JMX * specification implemented by this product. @@ -122,18 +112,6 @@ private JmxProperties() { public static final Logger MBEANSERVER_LOGGER = System.getLogger(MBEANSERVER_LOGGER_NAME); - /** - * Logger name for MLet service information. - */ - public static final String MLET_LOGGER_NAME = - "javax.management.mlet"; - - /** - * Logger for MLet service information. - */ - public static final Logger MLET_LOGGER = - System.getLogger(MLET_LOGGER_NAME); - /** * Logger name for Monitor information. */ diff --git a/src/java.management/share/classes/com/sun/jmx/defaults/ServiceName.java b/src/java.management/share/classes/com/sun/jmx/defaults/ServiceName.java index 8f742dff0f860..b194817848346 100644 --- a/src/java.management/share/classes/com/sun/jmx/defaults/ServiceName.java +++ b/src/java.management/share/classes/com/sun/jmx/defaults/ServiceName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, 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 @@ -44,14 +44,6 @@ private ServiceName() { public static final String DELEGATE = "JMImplementation:type=MBeanServerDelegate" ; - /** - * The default key properties for registering the class loader of the - * MLet service. - *
    - * The value is type=MLet. - */ - public static final String MLET = "type=MLet"; - /** * The default domain. *
    diff --git a/src/java.management/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java b/src/java.management/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java index 38050ca0d7a5f..a73e46e6020e8 100644 --- a/src/java.management/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java +++ b/src/java.management/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,18 +206,6 @@ private Class loadClass(final LoaderEntry list[], if (MBEANSERVER_LOGGER.isLoggable(Level.TRACE)) { MBEANSERVER_LOGGER.log(Level.TRACE, "Trying loader = " + cl); } - /* We used to have a special case for "instanceof - MLet" here, where we invoked the method - loadClass(className, null) to prevent infinite - recursion. But the rule whereby the MLet only - consults loaders that precede it in the CLR (via - loadClassBefore) means that the recursion can't - happen, and the test here caused some legitimate - classloading to fail. For example, if you have - dependencies C->D->E with loaders {E D C} in the - CLR in that order, you would expect to be able to - load C. The problem is that while resolving D, CLR - delegation is disabled, so it can't find E. */ return Class.forName(className, false, cl); } catch (ClassNotFoundException e) { // OK: continue with next class diff --git a/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java b/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java index ac9c8cfada994..c94750e99ff45 100644 --- a/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java +++ b/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -75,12 +75,11 @@ * inappropriate.

    * *

    If there is no SecurityManager, then the access controller will refuse - * to create an MBean that is a ClassLoader, which includes MLets, or to - * execute the method addURL on an MBean that is an MLet. This prevents + * to create an MBean that is a ClassLoader. This prevents * people from opening security holes unintentionally. Otherwise, it * would not be obvious that granting write access grants the ability to * download and execute arbitrary code in the target MBean server. Advanced - * users who do want the ability to use MLets are presumably advanced enough + * users who do want an MBean which is a ClassLoader are presumably advanced enough * to handle policy files and security managers.

    */ public abstract class MBeanServerAccessController @@ -468,7 +467,6 @@ public Object invoke(ObjectName name, String operationName, MBeanException, ReflectionException { checkWrite(); - checkMLetMethods(name, operationName); return getMBeanServer().invoke(name, operationName, params, signature); } @@ -620,49 +618,6 @@ private void checkClassLoader(Object object) { "manager is installed."); } - private void checkMLetMethods(ObjectName name, String operation) - throws InstanceNotFoundException { - // Check if security manager installed - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - return; - } - // Check for addURL and getMBeansFromURL methods - if (!operation.equals("addURL") && - !operation.equals("getMBeansFromURL")) { - return; - } - // Check if MBean is instance of MLet - if (!getMBeanServer().isInstanceOf(name, - "javax.management.loading.MLet")) { - return; - } - // Throw security exception - if (operation.equals("addURL")) { // addURL - throw new SecurityException("Access denied! MLet method addURL " + - "cannot be invoked unless a security manager is installed."); - } else { // getMBeansFromURL - // Whether or not calling getMBeansFromURL is allowed is controlled - // by the value of the "jmx.remote.x.mlet.allow.getMBeansFromURL" - // system property. If the value of this property is true, calling - // the MLet's getMBeansFromURL method is allowed. The default value - // for this property is false. - final String propName = "jmx.remote.x.mlet.allow.getMBeansFromURL"; - GetPropertyAction propAction = new GetPropertyAction(propName); - @SuppressWarnings("removal") - String propValue = AccessController.doPrivileged(propAction); - boolean allowGetMBeansFromURL = "true".equalsIgnoreCase(propValue); - if (!allowGetMBeansFromURL) { - throw new SecurityException("Access denied! MLet method " + - "getMBeansFromURL cannot be invoked unless a " + - "security manager is installed or the system property " + - "-Djmx.remote.x.mlet.allow.getMBeansFromURL=true " + - "is specified."); - } - } - } - //------------------ // PRIVATE VARIABLES //------------------ diff --git a/src/java.management/share/classes/javax/management/loading/MLet.java b/src/java.management/share/classes/javax/management/loading/MLet.java deleted file mode 100644 index aacf73e482190..0000000000000 --- a/src/java.management/share/classes/javax/management/loading/MLet.java +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javax.management.loading; - -import com.sun.jmx.defaults.ServiceName; - -import com.sun.jmx.remote.util.EnvHelp; - -import java.io.Externalizable; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInput; -import java.io.ObjectInputStream; -import java.io.ObjectOutput; -import java.lang.reflect.Constructor; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLStreamHandlerFactory; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.lang.System.Logger.Level; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanRegistration; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectInstance; -import javax.management.ObjectName; -import javax.management.ReflectionException; - -import static com.sun.jmx.defaults.JmxProperties.MLET_LIB_DIR; -import static com.sun.jmx.defaults.JmxProperties.MLET_LOGGER; -import javax.management.ServiceNotFoundException; - -/** - * Allows you to instantiate and register one or several MBeans in the MBean server - * coming from a remote URL. M-let is a shortcut for management applet. The m-let service does this - * by loading an m-let text file, which specifies information on the MBeans to be obtained. - * The information on each MBean is specified in a single instance of a tag, called the MLET tag. - * The location of the m-let text file is specified by a URL. - *

    - * The MLET tag has the following syntax: - *

    - * <MLET
    - * CODE = class | OBJECT = serfile
    - * ARCHIVE = "archiveList"
    - * [CODEBASE = codebaseURL]
    - * [NAME = mbeanname]
    - * [VERSION = version]
    - * >
    - * [arglist]
    - * </MLET> - *

    - * where: - *

    - *
    CODE = class
    - *
    - * This attribute specifies the full Java class name, including package name, of the MBean to be obtained. - * The compiled .class file of the MBean must be contained in one of the .jar files specified by the ARCHIVE - * attribute. Either CODE or OBJECT must be present. - *
    - *
    OBJECT = serfile
    - *
    - * This attribute specifies the .ser file that contains a serialized representation of the MBean to be obtained. - * This file must be contained in one of the .jar files specified by the ARCHIVE attribute. If the .jar file contains a directory hierarchy, specify the path of the file within this hierarchy. Otherwise a match will not be found. Either CODE or OBJECT must be present. - *
    - *
    ARCHIVE = "archiveList"
    - *
    - * This mandatory attribute specifies one or more .jar files - * containing MBeans or other resources used by - * the MBean to be obtained. One of the .jar files must contain the file specified by the CODE or OBJECT attribute. - * If archivelist contains more than one file: - *
      - *
    • Each file must be separated from the one that follows it by a comma (,). - *
    • archivelist must be enclosed in double quote marks. - *
    - * All .jar files in archivelist must be stored in the directory specified by the code base URL. - *
    - *
    CODEBASE = codebaseURL
    - *
    - * This optional attribute specifies the code base URL of the MBean to be obtained. It identifies the directory that contains - * the .jar files specified by the ARCHIVE attribute. Specify this attribute only if the .jar files are not in the same - * directory as the m-let text file. If this attribute is not specified, the base URL of the m-let text file is used. - *
    - *
    NAME = mbeanname
    - *
    - * This optional attribute specifies the object name to be assigned to the - * MBean instance when the m-let service registers it. If - * mbeanname starts with the colon character (:), the domain - * part of the object name is the default domain of the MBean server, - * as returned by {@link javax.management.MBeanServer#getDefaultDomain()}. - *
    - *
    VERSION = version
    - *
    - * This optional attribute specifies the version number of the MBean and - * associated .jar files to be obtained. This version number can - * be used to specify that the .jar files are loaded from the - * server to update those stored locally in the cache the next time the m-let - * text file is loaded. version must be a series of non-negative - * decimal integers each separated by a period from the one that precedes it. - *
    - *
    arglist
    - *
    - * This optional attribute specifies a list of one or more parameters for the - * MBean to be instantiated. This list describes the parameters to be passed the MBean's constructor. - * Use the following syntax to specify each item in - * arglist: - *
    - *
    <ARG TYPE=argumentType VALUE=value>
    - *
    where: - *
      - *
    • argumentType is the type of the argument that will be passed as parameter to the MBean's constructor.
    - *
    - *
    - *

    The arguments' type in the argument list should be a Java primitive type or a Java basic type - * (java.lang.Boolean, java.lang.Byte, java.lang.Short, java.lang.Long, java.lang.Integer, java.lang.Float, java.lang.Double, java.lang.String). - *

    - *
    - * - * When an m-let text file is loaded, an - * instance of each MBean specified in the file is created and registered. - *

    - * The m-let service extends the java.net.URLClassLoader and can be used to load remote classes - * and jar files in the VM of the agent. - *

    Note - The MLet class loader uses the {@link javax.management.MBeanServerFactory#getClassLoaderRepository(javax.management.MBeanServer)} - * to load classes that could not be found in the loaded jar files. - * - * @deprecated This API is part of Management Applets (m-lets), which is a legacy feature that allows loading - * of remote MBeans. This feature is not usable without a Security Manager, which is deprecated and subject to - * removal in a future release. Consequently, this API is also deprecated and subject to removal. There is no replacement. - * - * @since 1.5 - */ -@Deprecated(since="20", forRemoval=true) -@SuppressWarnings("removal") -public class MLet extends java.net.URLClassLoader - implements MLetMBean, MBeanRegistration, Externalizable { - - private static final long serialVersionUID = 3636148327800330130L; - - /* - * ------------------------------------------ - * PRIVATE VARIABLES - * ------------------------------------------ - */ - - /** - * The reference to the MBean server. - * @serial - */ - @SuppressWarnings("serial") // Type of field is not Serializable - private MBeanServer server = null; - - - /** - * The list of instances of the MLetContent - * class found at the specified URL. - * @serial - */ - @SuppressWarnings("serial") // Type of field is not Serializable - private List mletList = new ArrayList<>(); - - - /** - * The directory used for storing libraries locally before they are loaded. - */ - private String libraryDirectory; - - - /** - * The object name of the MLet Service. - * @serial - */ - private ObjectName mletObjectName = null; - - /** - * The URLs of the MLet Service. - * @serial - */ - private URL[] myUrls = null; - - /** - * What ClassLoaderRepository, if any, to use if this MLet - * doesn't find an asked-for class. - */ - private transient ClassLoaderRepository currentClr; - - /** - * True if we should consult the {@link ClassLoaderRepository} - * when we do not find a class ourselves. - */ - private transient boolean delegateToCLR; - - /** - * objects maps from primitive classes to primitive object classes. - */ - @SuppressWarnings("serial") // Type of field is not Serializable - private Map> primitiveClasses = new HashMap<>(8) ; - { - primitiveClasses.put(Boolean.TYPE.toString(), Boolean.class); - primitiveClasses.put(Character.TYPE.toString(), Character.class); - primitiveClasses.put(Byte.TYPE.toString(), Byte.class); - primitiveClasses.put(Short.TYPE.toString(), Short.class); - primitiveClasses.put(Integer.TYPE.toString(), Integer.class); - primitiveClasses.put(Long.TYPE.toString(), Long.class); - primitiveClasses.put(Float.TYPE.toString(), Float.class); - primitiveClasses.put(Double.TYPE.toString(), Double.class); - - } - - - /* - * ------------------------------------------ - * CONSTRUCTORS - * ------------------------------------------ - */ - - /* - * The constructor stuff would be considerably simplified if our - * parent, URLClassLoader, specified that its one- and - * two-argument constructors were equivalent to its - * three-argument constructor with trailing null arguments. But - * it doesn't, which prevents us from having all the constructors - * but one call this(...args...). - */ - - /** - * Constructs a new MLet using the default delegation parent ClassLoader. - */ - public MLet() { - this(new URL[0]); - } - - /** - * Constructs a new MLet for the specified URLs using the default - * delegation parent ClassLoader. The URLs will be searched in - * the order specified for classes and resources after first - * searching in the parent class loader. - * - * @param urls The URLs from which to load classes and resources. - * - */ - public MLet(URL[] urls) { - this(urls, true); - } - - /** - * Constructs a new MLet for the given URLs. The URLs will be - * searched in the order specified for classes and resources - * after first searching in the specified parent class loader. - * The parent argument will be used as the parent class loader - * for delegation. - * - * @param urls The URLs from which to load classes and resources. - * @param parent The parent class loader for delegation. - * - */ - public MLet(URL[] urls, ClassLoader parent) { - this(urls, parent, true); - } - - /** - * Constructs a new MLet for the specified URLs, parent class - * loader, and URLStreamHandlerFactory. The parent argument will - * be used as the parent class loader for delegation. The factory - * argument will be used as the stream handler factory to obtain - * protocol handlers when creating new URLs. - * - * @param urls The URLs from which to load classes and resources. - * @param parent The parent class loader for delegation. - * @param factory The URLStreamHandlerFactory to use when creating URLs. - * - */ - public MLet(URL[] urls, - ClassLoader parent, - URLStreamHandlerFactory factory) { - this(urls, parent, factory, true); - } - - /** - * Constructs a new MLet for the specified URLs using the default - * delegation parent ClassLoader. The URLs will be searched in - * the order specified for classes and resources after first - * searching in the parent class loader. - * - * @param urls The URLs from which to load classes and resources. - * @param delegateToCLR True if, when a class is not found in - * either the parent ClassLoader or the URLs, the MLet should delegate - * to its containing MBeanServer's {@link ClassLoaderRepository}. - * - */ - public MLet(URL[] urls, boolean delegateToCLR) { - super(urls); - init(delegateToCLR); - } - - /** - * Constructs a new MLet for the given URLs. The URLs will be - * searched in the order specified for classes and resources - * after first searching in the specified parent class loader. - * The parent argument will be used as the parent class loader - * for delegation. - * - * @param urls The URLs from which to load classes and resources. - * @param parent The parent class loader for delegation. - * @param delegateToCLR True if, when a class is not found in - * either the parent ClassLoader or the URLs, the MLet should delegate - * to its containing MBeanServer's {@link ClassLoaderRepository}. - * - */ - public MLet(URL[] urls, ClassLoader parent, boolean delegateToCLR) { - super(urls, parent); - init(delegateToCLR); - } - - /** - * Constructs a new MLet for the specified URLs, parent class - * loader, and URLStreamHandlerFactory. The parent argument will - * be used as the parent class loader for delegation. The factory - * argument will be used as the stream handler factory to obtain - * protocol handlers when creating new URLs. - * - * @param urls The URLs from which to load classes and resources. - * @param parent The parent class loader for delegation. - * @param factory The URLStreamHandlerFactory to use when creating URLs. - * @param delegateToCLR True if, when a class is not found in - * either the parent ClassLoader or the URLs, the MLet should delegate - * to its containing MBeanServer's {@link ClassLoaderRepository}. - * - */ - public MLet(URL[] urls, - ClassLoader parent, - URLStreamHandlerFactory factory, - boolean delegateToCLR) { - super(urls, parent, factory); - init(delegateToCLR); - } - - private void init(boolean delegateToCLR) { - this.delegateToCLR = delegateToCLR; - - try { - libraryDirectory = System.getProperty(MLET_LIB_DIR); - if (libraryDirectory == null) - libraryDirectory = getTmpDir(); - } catch (SecurityException e) { - // OK : We don't do AccessController.doPrivileged, but we don't - // stop the user from creating an MLet just because they - // can't read the MLET_LIB_DIR or java.io.tmpdir properties - // either. - } - } - - - /* - * ------------------------------------------ - * PUBLIC METHODS - * ------------------------------------------ - */ - - - /** - * Appends the specified URL to the list of URLs to search for classes and - * resources. - */ - public void addURL(URL url) { - if (!Arrays.asList(getURLs()).contains(url)) - super.addURL(url); - } - - /** - * Appends the specified URL to the list of URLs to search for classes and - * resources. - * @exception ServiceNotFoundException The specified URL is malformed. - */ - public void addURL(String url) throws ServiceNotFoundException { - try { - @SuppressWarnings("deprecation") - URL ur = new URL(url); - if (!Arrays.asList(getURLs()).contains(ur)) - super.addURL(ur); - } catch (MalformedURLException e) { - if (MLET_LOGGER.isLoggable(Level.DEBUG)) { - MLET_LOGGER.log(Level.DEBUG, "Malformed URL: " + url, e); - } - throw new - ServiceNotFoundException("The specified URL is malformed"); - } - } - - /** Returns the search path of URLs for loading classes and resources. - * This includes the original list of URLs specified to the constructor, - * along with any URLs subsequently appended by the addURL() method. - */ - public URL[] getURLs() { - return super.getURLs(); - } - - /** - * Loads a text file containing MLET tags that define the MBeans to - * be added to the MBean server. The location of the text file is specified by - * a URL. The MBeans specified in the MLET file will be instantiated and - * registered in the MBean server. - * - * @param url The URL of the text file to be loaded as URL object. - * - * @return A set containing one entry per MLET tag in the m-let text file loaded. - * Each entry specifies either the ObjectInstance for the created MBean, or a throwable object - * (that is, an error or an exception) if the MBean could not be created. - * - * @exception ServiceNotFoundException One of the following errors has occurred: The m-let text file does - * not contain an MLET tag, the m-let text file is not found, a mandatory - * attribute of the MLET tag is not specified, the value of url is - * null. - * @exception IllegalStateException MLet MBean is not registered with an MBeanServer. - */ - public Set getMBeansFromURL(URL url) - throws ServiceNotFoundException { - if (url == null) { - throw new ServiceNotFoundException("The specified URL is null"); - } - return getMBeansFromURL(url.toString()); - } - - /** - * Loads a text file containing MLET tags that define the MBeans to - * be added to the MBean server. The location of the text file is specified by - * a URL. The MBeans specified in the MLET file will be instantiated and - * registered in the MBean server. - * - * @param url The URL of the text file to be loaded as String object. - * - * @return A set containing one entry per MLET tag in the m-let - * text file loaded. Each entry specifies either the - * ObjectInstance for the created MBean, or a throwable object - * (that is, an error or an exception) if the MBean could not be - * created. - * - * @exception ServiceNotFoundException One of the following - * errors has occurred: The m-let text file does not contain an - * MLET tag, the m-let text file is not found, a mandatory - * attribute of the MLET tag is not specified, the url is - * malformed. - * @exception IllegalStateException MLet MBean is not registered - * with an MBeanServer. - * - */ - public Set getMBeansFromURL(String url) - throws ServiceNotFoundException { - - if (server == null) { - throw new IllegalStateException("This MLet MBean is not " + - "registered with an MBeanServer."); - } - // Parse arguments - if (url == null) { - MLET_LOGGER.log(Level.TRACE, "URL is null"); - throw new ServiceNotFoundException("The specified URL is null"); - } else { - url = url.replace(File.separatorChar,'/'); - } - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, ""); - } - - // Parse URL - try { - MLetParser parser = new MLetParser(); - mletList = parser.parseURL(url); - } catch (Exception e) { - final String msg = - "Problems while parsing URL [" + url + - "], got exception [" + e.toString() + "]"; - MLET_LOGGER.log(Level.TRACE, msg); - throw EnvHelp.initCause(new ServiceNotFoundException(msg), e); - } - - // Check that the list of MLets is not empty - if (mletList.size() == 0) { - final String msg = - "File " + url + " not found or MLET tag not defined in file"; - MLET_LOGGER.log(Level.TRACE, msg); - throw new ServiceNotFoundException(msg); - } - - // Walk through the list of MLets - Set mbeans = new HashSet<>(); - for (MLetContent elmt : mletList) { - // Initialize local variables - String code = elmt.getCode(); - if (code != null) { - if (code.endsWith(".class")) { - code = code.substring(0, code.length() - 6); - } - } - String name = elmt.getName(); - URL codebase = elmt.getCodeBase(); - String version = elmt.getVersion(); - String serName = elmt.getSerializedObject(); - String jarFiles = elmt.getJarFiles(); - URL documentBase = elmt.getDocumentBase(); - - // Display debug information - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - final StringBuilder strb = new StringBuilder() - .append("\n\tMLET TAG = ").append(elmt.getAttributes()) - .append("\n\tCODEBASE = ").append(codebase) - .append("\n\tARCHIVE = ").append(jarFiles) - .append("\n\tCODE = ").append(code) - .append("\n\tOBJECT = ").append(serName) - .append("\n\tNAME = ").append(name) - .append("\n\tVERSION = ").append(version) - .append("\n\tDOCUMENT URL = ").append(documentBase); - MLET_LOGGER.log(Level.TRACE, strb::toString); - } - - // Load classes from JAR files - StringTokenizer st = new StringTokenizer(jarFiles, ",", false); - while (st.hasMoreTokens()) { - String tok = st.nextToken().trim(); - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Load archive for codebase <" + codebase + - ">, file <" + tok + ">"); - } - // Check which is the codebase to be used for loading the jar file. - // If we are using the base MLet implementation then it will be - // always the remote server but if the service has been extended in - // order to support caching and versioning then this method will - // return the appropriate one. - // - try { - codebase = check(version, codebase, tok, elmt); - } catch (Exception ex) { - MLET_LOGGER.log(Level.DEBUG, - "Got unexpected exception", ex); - mbeans.add(ex); - continue; - } - - // Appends the specified JAR file URL to the list of - // URLs to search for classes and resources. - try { - @SuppressWarnings("deprecation") - var u = new URL(codebase.toString() + tok); - if (!Arrays.asList(getURLs()) - .contains(u)) { - addURL(codebase + tok); - } - } catch (MalformedURLException me) { - // OK : Ignore jar file if its name provokes the - // URL to be an invalid one. - } - - } - // Instantiate the class specified in the - // CODE or OBJECT section of the MLet tag - // - Object o; - ObjectInstance objInst; - - if (code != null && serName != null) { - final String msg = - "CODE and OBJECT parameters cannot be specified at the " + - "same time in tag MLET"; - MLET_LOGGER.log(Level.TRACE, msg); - mbeans.add(new Error(msg)); - continue; - } - if (code == null && serName == null) { - final String msg = - "Either CODE or OBJECT parameter must be specified in " + - "tag MLET"; - MLET_LOGGER.log(Level.TRACE, msg); - mbeans.add(new Error(msg)); - continue; - } - try { - if (code != null) { - - List signat = elmt.getParameterTypes(); - List stringPars = elmt.getParameterValues(); - List objectPars = new ArrayList<>(); - - for (int i = 0; i < signat.size(); i++) { - objectPars.add(constructParameter(stringPars.get(i), - signat.get(i))); - } - if (signat.isEmpty()) { - if (name == null) { - objInst = server.createMBean(code, null, - mletObjectName); - } else { - objInst = server.createMBean(code, - new ObjectName(name), - mletObjectName); - } - } else { - Object[] parms = objectPars.toArray(); - String[] signature = new String[signat.size()]; - signat.toArray(signature); - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - final StringBuilder strb = new StringBuilder(); - for (int i = 0; i < signature.length; i++) { - strb.append("\n\tSignature = ") - .append(signature[i]) - .append("\t\nParams = ") - .append(parms[i]); - } - MLET_LOGGER.log(Level.TRACE, strb::toString); - } - if (name == null) { - objInst = - server.createMBean(code, null, mletObjectName, - parms, signature); - } else { - objInst = - server.createMBean(code, new ObjectName(name), - mletObjectName, parms, - signature); - } - } - } else { - o = loadSerializedObject(codebase,serName); - if (name == null) { - server.registerMBean(o, null); - } else { - server.registerMBean(o, new ObjectName(name)); - } - objInst = new ObjectInstance(name, o.getClass().getName()); - } - } catch (ReflectionException ex) { - MLET_LOGGER.log(Level.TRACE, "ReflectionException", ex); - mbeans.add(ex); - continue; - } catch (InstanceAlreadyExistsException ex) { - MLET_LOGGER.log(Level.TRACE, - "InstanceAlreadyExistsException", ex); - mbeans.add(ex); - continue; - } catch (MBeanRegistrationException ex) { - MLET_LOGGER.log(Level.TRACE, "MBeanRegistrationException", ex); - mbeans.add(ex); - continue; - } catch (MBeanException ex) { - MLET_LOGGER.log(Level.TRACE, "MBeanException", ex); - mbeans.add(ex); - continue; - } catch (NotCompliantMBeanException ex) { - MLET_LOGGER.log(Level.TRACE, - "NotCompliantMBeanException", ex); - mbeans.add(ex); - continue; - } catch (InstanceNotFoundException ex) { - MLET_LOGGER.log(Level.TRACE, - "InstanceNotFoundException", ex); - mbeans.add(ex); - continue; - } catch (IOException ex) { - MLET_LOGGER.log(Level.TRACE, "IOException", ex); - mbeans.add(ex); - continue; - } catch (SecurityException ex) { - MLET_LOGGER.log(Level.TRACE, "SecurityException", ex); - mbeans.add(ex); - continue; - } catch (Exception ex) { - MLET_LOGGER.log(Level.TRACE, "Exception", ex); - mbeans.add(ex); - continue; - } catch (Error ex) { - MLET_LOGGER.log(Level.TRACE, "Error", ex); - mbeans.add(ex); - continue; - } - mbeans.add(objInst); - } - return mbeans; - } - - /** - * Gets the current directory used by the library loader for - * storing native libraries before they are loaded into memory. - * - * @return The current directory used by the library loader. - * - * @see #setLibraryDirectory - * - * @throws UnsupportedOperationException if this implementation - * does not support storing native libraries in this way. - */ - public synchronized String getLibraryDirectory() { - return libraryDirectory; - } - - /** - * Sets the directory used by the library loader for storing - * native libraries before they are loaded into memory. - * - * @param libdir The directory used by the library loader. - * - * @see #getLibraryDirectory - * - * @throws UnsupportedOperationException if this implementation - * does not support storing native libraries in this way. - */ - public synchronized void setLibraryDirectory(String libdir) { - libraryDirectory = libdir; - } - - /** - * Allows the m-let to perform any operations it needs before - * being registered in the MBean server. If the ObjectName is - * null, the m-let provides a default name for its registration - * <defaultDomain>:type=MLet - * - * @param server The MBean server in which the m-let will be registered. - * @param name The object name of the m-let. - * - * @return The name of the m-let registered. - * - * @exception java.lang.Exception This exception should be caught by the MBean server and re-thrown - *as an MBeanRegistrationException. - */ - public ObjectName preRegister(MBeanServer server, ObjectName name) - throws Exception { - - // Initialize local pointer to the MBean server - setMBeanServer(server); - - // If no name is specified return a default name for the MLet - if (name == null) { - name = new ObjectName(server.getDefaultDomain() + ":" + ServiceName.MLET); - } - - this.mletObjectName = name; - return this.mletObjectName; - } - - /** - * Allows the m-let to perform any operations needed after having been - * registered in the MBean server or after the registration has failed. - * - * @param registrationDone Indicates whether or not the m-let has - * been successfully registered in the MBean server. The value - * false means that either the registration phase has failed. - * - */ - public void postRegister (Boolean registrationDone) { - } - - /** - * Allows the m-let to perform any operations it needs before being unregistered - * by the MBean server. - * - * @exception java.lang.Exception This exception should be caught - * by the MBean server and re-thrown as an - * MBeanRegistrationException. - */ - public void preDeregister() throws java.lang.Exception { - } - - - /** - * Allows the m-let to perform any operations needed after having been - * unregistered in the MBean server. - */ - public void postDeregister() { - } - - /** - *

    Save this MLet's contents to the given {@link ObjectOutput}. - * Not all implementations support this method. Those that do not - * throw {@link UnsupportedOperationException}. A subclass may - * override this method to support it or to change the format of - * the written data.

    - * - *

    The format of the written data is not specified, but if - * an implementation supports {@link #writeExternal} it must - * also support {@link #readExternal} in such a way that what is - * written by the former can be read by the latter.

    - * - * @param out The object output stream to write to. - * - * @exception IOException If a problem occurred while writing. - * @exception UnsupportedOperationException If this - * implementation does not support this operation. - */ - public void writeExternal(ObjectOutput out) - throws IOException, UnsupportedOperationException { - throw new UnsupportedOperationException("MLet.writeExternal"); - } - - /** - *

    Restore this MLet's contents from the given {@link ObjectInput}. - * Not all implementations support this method. Those that do not - * throw {@link UnsupportedOperationException}. A subclass may - * override this method to support it or to change the format of - * the read data.

    - * - *

    The format of the read data is not specified, but if an - * implementation supports {@link #readExternal} it must also - * support {@link #writeExternal} in such a way that what is - * written by the latter can be read by the former.

    - * - * @param in The object input stream to read from. - * - * @exception IOException if a problem occurred while reading. - * @exception ClassNotFoundException if the class for the object - * being restored cannot be found. - * @exception UnsupportedOperationException if this - * implementation does not support this operation. - */ - public void readExternal(ObjectInput in) - throws IOException, ClassNotFoundException, - UnsupportedOperationException { - throw new UnsupportedOperationException("MLet.readExternal"); - } - - /* - * ------------------------------------------ - * PACKAGE METHODS - * ------------------------------------------ - */ - - /** - *

    Load a class, using the given {@link ClassLoaderRepository} if - * the class is not found in this MLet's URLs. The given - * ClassLoaderRepository can be null, in which case a {@link - * ClassNotFoundException} occurs immediately if the class is not - * found in this MLet's URLs.

    - * - * @param name The name of the class we want to load. - * @param clr The ClassLoaderRepository that will be used to search - * for the given class, if it is not found in this - * ClassLoader. May be null. - * @return The resulting Class object. - * @exception ClassNotFoundException The specified class could not be - * found in this ClassLoader nor in the given - * ClassLoaderRepository. - * - */ - public synchronized Class loadClass(String name, - ClassLoaderRepository clr) - throws ClassNotFoundException { - final ClassLoaderRepository before=currentClr; - try { - currentClr = clr; - return loadClass(name); - } finally { - currentClr = before; - } - } - - /* - * ------------------------------------------ - * PROTECTED METHODS - * ------------------------------------------ - */ - - /** - * This is the main method for class loaders that is being redefined. - * - * @param name The name of the class. - * - * @return The resulting Class object. - * - * @exception ClassNotFoundException The specified class could not be - * found. - */ - protected Class findClass(String name) throws ClassNotFoundException { - /* currentClr is context sensitive - used to avoid recursion - in the class loader repository. (This is no longer - necessary with the new CLR semantics but is kept for - compatibility with code that might have called the - two-parameter loadClass explicitly.) */ - return findClass(name, currentClr); - } - - /** - * Called by {@link MLet#findClass(java.lang.String)}. - * - * @param name The name of the class that we want to load/find. - * @param clr The ClassLoaderRepository that can be used to search - * for the given class. This parameter is - * null when called from within the - * {@link javax.management.MBeanServerFactory#getClassLoaderRepository(javax.management.MBeanServer) Class Loader Repository}. - * @exception ClassNotFoundException The specified class could not be - * found. - * - **/ - Class findClass(String name, ClassLoaderRepository clr) - throws ClassNotFoundException { - Class c = null; - MLET_LOGGER.log(Level.TRACE, name); - // Try looking in the JAR: - try { - c = super.findClass(name); - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Class " + name + " loaded through MLet classloader"); - } - } catch (ClassNotFoundException e) { - // Drop through - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Class " + name + " not found locally"); - } - } - // if we are not called from the ClassLoaderRepository - if (c == null && delegateToCLR && clr != null) { - // Try the classloader repository: - // - try { - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Class " + name + " : looking in CLR"); - } - c = clr.loadClassBefore(this, name); - // The loadClassBefore method never returns null. - // If the class is not found we get an exception. - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Class " + name + " loaded through " + - "the default classloader repository"); - } - } catch (ClassNotFoundException e) { - // Drop through - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Class " + name + " not found in CLR"); - } - } - } - if (c == null) { - MLET_LOGGER.log(Level.TRACE, "Failed to load class " + name); - throw new ClassNotFoundException(name); - } - return c; - } - - /** - * Returns the absolute path name of a native library. The VM - * invokes this method to locate the native libraries that belong - * to classes loaded with this class loader. Libraries are - * searched in the JAR files using first just the native library - * name and if not found the native library name together with - * the architecture-specific path name - * (OSName/OSArch/OSVersion/lib/nativelibname), i.e. - *

    - * the library stat on Solaris SPARC 5.7 will be searched in the JAR file as: - *

      - *
    1. libstat.so - *
    2. SunOS/sparc/5.7/lib/libstat.so - *
    - * the library stat on Windows NT 4.0 will be searched in the JAR file as: - *
      - *
    1. stat.dll - *
    2. WindowsNT/x86/4.0/lib/stat.dll - *
    - * - *

    More specifically, let {@code nativelibname} be the result of - * {@link System#mapLibraryName(java.lang.String) - * System.mapLibraryName}{@code (libname)}. Then the following names are - * searched in the JAR files, in order:
    - * {@code nativelibname}
    - * {@code ///lib/}{@code nativelibname}
    - * where {@code } means {@code System.getProperty(X)} with any - * spaces in the result removed, and {@code /} stands for the - * file separator character ({@link File#separator}). - *

    - * If this method returns null, i.e. the libraries - * were not found in any of the JAR files loaded with this class - * loader, the VM searches the library along the path specified - * as the java.library.path property. - * - * @param libname The library name. - * - * @return The absolute path of the native library. - */ - protected String findLibrary(String libname) { - - String abs_path; - String mth = "findLibrary"; - - // Get the platform-specific string representing a native library. - // - String nativelibname = System.mapLibraryName(libname); - - // - // See if the native library is accessible as a resource through the JAR file. - // - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "Search " + libname + " in all JAR files"); - } - - // First try to locate the library in the JAR file using only - // the native library name. e.g. if user requested a load - // for "foo" on Solaris SPARC 5.7 we try to load "libfoo.so" - // from the JAR file. - // - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "loadLibraryAsResource(" + nativelibname + ")"); - } - abs_path = loadLibraryAsResource(nativelibname); - if (abs_path != null) { - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - nativelibname + " loaded, absolute path = " + abs_path); - } - return abs_path; - } - - // Next try to locate it using the native library name and - // the architecture-specific path name. e.g. if user - // requested a load for "foo" on Solaris SPARC 5.7 we try to - // load "SunOS/sparc/5.7/lib/libfoo.so" from the JAR file. - // - nativelibname = removeSpace(System.getProperty("os.name")) + File.separator + - removeSpace(System.getProperty("os.arch")) + File.separator + - removeSpace(System.getProperty("os.version")) + File.separator + - "lib" + File.separator + nativelibname; - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - "loadLibraryAsResource(" + nativelibname + ")"); - } - - abs_path = loadLibraryAsResource(nativelibname); - if (abs_path != null) { - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - nativelibname + " loaded, absolute path = " + abs_path); - } - return abs_path; - } - - // - // All paths exhausted, library not found in JAR file. - // - - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, - libname + " not found in any JAR file"); - MLET_LOGGER.log(Level.TRACE, - "Search " + libname + " along the path " + - "specified as the java.library.path property"); - } - - // Let the VM search the library along the path - // specified as the java.library.path property. - // - return null; - } - - - /* - * ------------------------------------------ - * PRIVATE METHODS - * ------------------------------------------ - */ - - private String getTmpDir() { - // JDK 1.4 - String tmpDir = System.getProperty("java.io.tmpdir"); - if (tmpDir != null) return tmpDir; - - // JDK < 1.4 - File tmpFile = null; - try { - // Try to guess the system temporary dir... - tmpFile = File.createTempFile("tmp","jmx"); - if (tmpFile == null) return null; - final File tmpDirFile = tmpFile.getParentFile(); - if (tmpDirFile == null) return null; - return tmpDirFile.getAbsolutePath(); - } catch (Exception x) { - MLET_LOGGER.log(Level.DEBUG, - "Failed to determine system temporary dir"); - return null; - } finally { - // Cleanup ... - if (tmpFile!=null) { - try { - boolean deleted = tmpFile.delete(); - if (!deleted) { - MLET_LOGGER.log(Level.DEBUG, - "Failed to delete temp file"); - } - } catch (Exception x) { - MLET_LOGGER.log(Level.DEBUG, - "Failed to delete temporary file", x); - } - } - } - } - - /** - * Search the specified native library in any of the JAR files - * loaded by this classloader. If the library is found copy it - * into the library directory and return the absolute path. If - * the library is not found then return null. - */ - private synchronized String loadLibraryAsResource(String libname) { - try { - InputStream is = getResourceAsStream( - libname.replace(File.separatorChar,'/')); - if (is != null) { - try { - File directory = new File(libraryDirectory); - directory.mkdirs(); - File file = Files.createTempFile(directory.toPath(), - libname + ".", null) - .toFile(); - file.deleteOnExit(); - Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING); - return file.getAbsolutePath(); - } finally { - is.close(); - } - } - } catch (Exception e) { - MLET_LOGGER.log(Level.DEBUG, - "Failed to load library : " + libname, e); - return null; - } - return null; - } - - /** - * Removes any white space from a string. This is used to - * convert strings such as "Windows NT" to "WindowsNT". - */ - private static String removeSpace(String s) { - return s.trim().replace(" ", ""); - } - - /** - *

    This method is to be overridden when extending this service to - * support caching and versioning. It is called from {@link - * #getMBeansFromURL getMBeansFromURL} when the version, - * codebase, and jarfile have been extracted from the MLet file, - * and can be used to verify that it is all right to load the - * given MBean, or to replace the given URL with a different one.

    - * - *

    The default implementation of this method returns - * codebase unchanged.

    - * - * @param version The version number of the .jar - * file stored locally. - * @param codebase The base URL of the remote .jar file. - * @param jarfile The name of the .jar file to be loaded. - * @param mlet The MLetContent instance that - * represents the MLET tag. - * - * @return the codebase to use for the loaded MBean. The returned - * value should not be null. - * - * @exception Exception if the MBean is not to be loaded for some - * reason. The exception will be added to the set returned by - * {@link #getMBeansFromURL getMBeansFromURL}. - * - */ - protected URL check(String version, URL codebase, String jarfile, - MLetContent mlet) - throws Exception { - return codebase; - } - - /** - * Loads the serialized object specified by the OBJECT - * attribute of the MLET tag. - * - * @param codebase The codebase. - * @param filename The name of the file containing the serialized object. - * @return The serialized object. - * @exception ClassNotFoundException The specified serialized - * object could not be found. - * @exception IOException An I/O error occurred while loading - * serialized object. - */ - private Object loadSerializedObject(URL codebase, String filename) - throws IOException, ClassNotFoundException { - if (filename != null) { - filename = filename.replace(File.separatorChar,'/'); - } - if (MLET_LOGGER.isLoggable(Level.TRACE)) { - MLET_LOGGER.log(Level.TRACE, codebase.toString() + filename); - } - InputStream is = getResourceAsStream(filename); - if (is != null) { - try { - ObjectInputStream ois = new MLetObjectInputStream(is, this); - Object serObject = ois.readObject(); - ois.close(); - return serObject; - } catch (IOException | ClassNotFoundException e) { - if (MLET_LOGGER.isLoggable(Level.DEBUG)) { - MLET_LOGGER.log(Level.DEBUG, - "Exception while deserializing " + filename, e); - } - throw e; - } - } else { - if (MLET_LOGGER.isLoggable(Level.DEBUG)) { - MLET_LOGGER.log(Level.DEBUG, "Error: File " + filename + - " containing serialized object not found"); - } - throw new Error("File " + filename + " containing serialized object not found"); - } - } - - /** - * Converts the String value of the constructor's parameter to - * a basic Java object with the type of the parameter. - */ - private Object constructParameter(String param, String type) { - // check if it is a primitive type - Class c = primitiveClasses.get(type); - if (c != null) { - try { - Constructor cons = - c.getConstructor(String.class); - Object[] oo = new Object[1]; - oo[0]=param; - return(cons.newInstance(oo)); - - } catch (Exception e) { - MLET_LOGGER.log(Level.DEBUG, "Got unexpected exception", e); - } - } - return switch (type) { - case "java.lang.Boolean" -> Boolean.valueOf(param); - case "java.lang.Byte" -> Byte.valueOf(param); - case "java.lang.Short" -> Short.valueOf(param); - case "java.lang.Long" -> Long.valueOf(param); - case "java.lang.Integer" -> Integer.valueOf(param); - case "java.lang.Float" -> Float.valueOf(param); - case "java.lang.Double" -> Double.valueOf(param); - default -> param; - }; - } - - @SuppressWarnings("removal") - private synchronized void setMBeanServer(final MBeanServer server) { - this.server = server; - PrivilegedAction act = - new PrivilegedAction<>() { - public ClassLoaderRepository run() { - return server.getClassLoaderRepository(); - } - }; - currentClr = AccessController.doPrivileged(act); - } - -} diff --git a/src/java.management/share/classes/javax/management/loading/MLetContent.java b/src/java.management/share/classes/javax/management/loading/MLetContent.java deleted file mode 100644 index 638f7b38c2106..0000000000000 --- a/src/java.management/share/classes/javax/management/loading/MLetContent.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javax.management.loading; - - -// java import - -import java.net.URL; -import java.net.MalformedURLException; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * This class represents the contents of the MLET tag. - * It can be consulted by a subclass of {@link MLet} that overrides - * the {@link MLet#check MLet.check} method. - * - * @deprecated This API is part of Management Applets (m-lets), which is a legacy feature that allows loading - * of remote MBeans. This feature is not usable without a Security Manager, which is deprecated and subject to - * removal in a future release. Consequently, this API is also deprecated and subject to removal. There is no replacement. - * - * @since 1.6 - */ -@Deprecated(since="20", forRemoval=true) -public class MLetContent { - - /** - * A map of the attributes of the MLET tag - * and their values. - */ - private Map attributes; - - /** - * An ordered list of the TYPE attributes that appeared in nested - * <PARAM> tags. - */ - private List types; - - /** - * An ordered list of the VALUE attributes that appeared in nested - * <PARAM> tags. - */ - private List values; - - /** - * The MLet text file's base URL. - */ - private URL documentURL; - /** - * The base URL. - */ - private URL baseURL; - - - /** - * Creates an MLet instance initialized with attributes read - * from an MLET tag in an MLet text file. - * - * @param url The URL of the MLet text file containing the - * MLET tag. - * @param attributes A map of the attributes of the MLET tag. - * The keys in this map are the attribute names in lowercase, for - * example codebase. The values are the associated attribute - * values. - * @param types A list of the TYPE attributes that appeared in nested - * <PARAM> tags. - * @param values A list of the VALUE attributes that appeared in nested - * <PARAM> tags. - */ - public MLetContent(URL url, Map attributes, - List types, List values) { - this.documentURL = url; - this.attributes = Collections.unmodifiableMap(attributes); - this.types = Collections.unmodifiableList(types); - this.values = Collections.unmodifiableList(values); - - // Initialize baseURL - // - String att = getParameter("codebase"); - if (att != null) { - if (!att.endsWith("/")) { - att += "/"; - } - try { - @SuppressWarnings("deprecation") - var _unused = baseURL = new URL(documentURL, att); - } catch (MalformedURLException e) { - // OK : Move to next block as baseURL could not be initialized. - } - } - if (baseURL == null) { - String file = documentURL.getFile(); - int i = file.lastIndexOf('/'); - if (i >= 0 && i < file.length() - 1) { - try { - @SuppressWarnings("deprecation") - var _unused = baseURL = new URL(documentURL, file.substring(0, i + 1)); - } catch (MalformedURLException e) { - // OK : Move to next block as baseURL could not be initialized. - } - } - } - if (baseURL == null) - baseURL = documentURL; - - } - - // GETTERS AND SETTERS - //-------------------- - - /** - * Gets the attributes of the MLET tag. The keys in - * the returned map are the attribute names in lowercase, for - * example codebase. The values are the associated - * attribute values. - * @return A map of the attributes of the MLET tag - * and their values. - */ - public Map getAttributes() { - return attributes; - } - - /** - * Gets the MLet text file's base URL. - * @return The MLet text file's base URL. - */ - public URL getDocumentBase() { - return documentURL; - } - - /** - * Gets the code base URL. - * @return The code base URL. - */ - public URL getCodeBase() { - return baseURL; - } - - /** - * Gets the list of .jar files specified by the ARCHIVE - * attribute of the MLET tag. - * @return A comma-separated list of .jar file names. - */ - public String getJarFiles() { - return getParameter("archive"); - } - - /** - * Gets the value of the CODE - * attribute of the MLET tag. - * @return The value of the CODE - * attribute of the MLET tag. - */ - public String getCode() { - return getParameter("code"); - } - - /** - * Gets the value of the OBJECT - * attribute of the MLET tag. - * @return The value of the OBJECT - * attribute of the MLET tag. - */ - public String getSerializedObject() { - return getParameter("object"); - } - - /** - * Gets the value of the NAME - * attribute of the MLET tag. - * @return The value of the NAME - * attribute of the MLET tag. - */ - public String getName() { - return getParameter("name"); - } - - - /** - * Gets the value of the VERSION - * attribute of the MLET tag. - * @return The value of the VERSION - * attribute of the MLET tag. - */ - public String getVersion() { - return getParameter("version"); - } - - /** - * Gets the list of values of the TYPE attribute in - * each nested <PARAM> tag within the MLET - * tag. - * @return the list of types. - */ - public List getParameterTypes() { - return types; - } - - /** - * Gets the list of values of the VALUE attribute in - * each nested <PARAM> tag within the MLET - * tag. - * @return the list of values. - */ - public List getParameterValues() { - return values; - } - - /** - * Gets the value of the specified - * attribute of the MLET tag. - * - * @param name A string representing the name of the attribute. - * @return The value of the specified - * attribute of the MLET tag. - */ - private String getParameter(String name) { - return attributes.get(name.toLowerCase()); - } - -} diff --git a/src/java.management/share/classes/javax/management/loading/MLetMBean.java b/src/java.management/share/classes/javax/management/loading/MLetMBean.java deleted file mode 100644 index 1e57cef9be782..0000000000000 --- a/src/java.management/share/classes/javax/management/loading/MLetMBean.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javax.management.loading; - -import java.net.URL; -import java.io.InputStream; -import java.io.IOException; -import java.util.Set; -import java.util.Enumeration; - -import javax.management.*; - - - -/** - * Exposes the remote management interface of the MLet - * MBean. - * - * @deprecated This API is part of Management Applets (m-lets), which is a legacy feature that allows loading - * of remote MBeans. This feature is not usable without a Security Manager, which is deprecated and subject to - * removal in a future release. Consequently, this API is also deprecated and subject to removal. There is no replacement. - * - * @since 1.5 - */ -@Deprecated(since="20", forRemoval=true) -public interface MLetMBean { - - /** - * Loads a text file containing MLET tags that define the MBeans - * to be added to the MBean server. The location of the text file is - * specified by a URL. The text file is read using the UTF-8 - * encoding. The MBeans specified in the MLET file will be - * instantiated and registered in the MBean server. - * - * @param url The URL of the text file to be loaded as String object. - * - * @return A set containing one entry per MLET tag in the m-let - * text file loaded. Each entry specifies either the - * ObjectInstance for the created MBean, or a throwable object - * (that is, an error or an exception) if the MBean could not be - * created. - * - * @exception ServiceNotFoundException One of the following errors - * has occurred: The m-let text file does not contain an MLET tag, - * the m-let text file is not found, a mandatory attribute of the - * MLET tag is not specified, the value of url is malformed. - */ - public Set getMBeansFromURL(String url) - throws ServiceNotFoundException; - - /** - * Loads a text file containing MLET tags that define the MBeans - * to be added to the MBean server. The location of the text file is - * specified by a URL. The text file is read using the UTF-8 - * encoding. The MBeans specified in the MLET file will be - * instantiated and registered in the MBean server. - * - * @param url The URL of the text file to be loaded as URL object. - * - * @return A set containing one entry per MLET tag in the m-let - * text file loaded. Each entry specifies either the - * ObjectInstance for the created MBean, or a throwable object - * (that is, an error or an exception) if the MBean could not be - * created. - * - * @exception ServiceNotFoundException One of the following errors - * has occurred: The m-let text file does not contain an MLET tag, - * the m-let text file is not found, a mandatory attribute of the - * MLET tag is not specified, the value of url is null. - */ - public Set getMBeansFromURL(URL url) - throws ServiceNotFoundException; - - /** - * Appends the specified URL to the list of URLs to search for classes and - * resources. - * - * @param url the URL to add. - */ - public void addURL(URL url) ; - - /** - * Appends the specified URL to the list of URLs to search for classes and - * resources. - * - * @param url the URL to add. - * - * @exception ServiceNotFoundException The specified URL is malformed. - */ - public void addURL(String url) throws ServiceNotFoundException; - - /** - * Returns the search path of URLs for loading classes and resources. - * This includes the original list of URLs specified to the constructor, - * along with any URLs subsequently appended by the addURL() method. - * - * @return the list of URLs. - */ - public URL[] getURLs(); - - /** Finds the resource with the given name. - * A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is - * independent of the location of the code. - * The name of a resource is a "/"-separated path name that identifies the resource. - * - * @param name The resource name - * - * @return An URL for reading the resource, or null if the resource could not be found or the caller doesn't have adequate privileges to get the - * resource. - */ - public URL getResource(String name); - - /** Returns an input stream for reading the specified resource. The search order is described in the documentation for - * getResource(String). - * - * @param name The resource name - * - * @return An input stream for reading the resource, or null if the resource could not be found - * - */ - public InputStream getResourceAsStream(String name); - - /** - * Finds all the resources with the given name. A resource is some - * data (images, audio, text, etc) that can be accessed by class - * code in a way that is independent of the location of the code. - * The name of a resource is a "/"-separated path name that - * identifies the resource. - * - * @param name The resource name. - * - * @return An enumeration of URL to the resource. If no resources - * could be found, the enumeration will be empty. Resources that - * cannot be accessed will not be in the enumeration. - * - * @exception IOException if an I/O exception occurs when - * searching for resources. - */ - public Enumeration getResources(String name) throws IOException; - - /** - * Gets the current directory used by the library loader for - * storing native libraries before they are loaded into memory. - * - * @return The current directory used by the library loader. - * - * @see #setLibraryDirectory - * - * @throws UnsupportedOperationException if this implementation - * does not support storing native libraries in this way. - */ - public String getLibraryDirectory(); - - /** - * Sets the directory used by the library loader for storing - * native libraries before they are loaded into memory. - * - * @param libdir The directory used by the library loader. - * - * @see #getLibraryDirectory - * - * @throws UnsupportedOperationException if this implementation - * does not support storing native libraries in this way. - */ - public void setLibraryDirectory(String libdir); - - } diff --git a/src/java.management/share/classes/javax/management/loading/MLetObjectInputStream.java b/src/java.management/share/classes/javax/management/loading/MLetObjectInputStream.java deleted file mode 100644 index 159fa85b22ea1..0000000000000 --- a/src/java.management/share/classes/javax/management/loading/MLetObjectInputStream.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javax.management.loading; - - -// java import - -import java.io.*; -import java.lang.reflect.Array; - - -/** - * This subclass of ObjectInputStream delegates loading of classes to - * an existing MLetClassLoader. - * - * @since 1.5 - */ -@Deprecated(since="20", forRemoval=true) -class MLetObjectInputStream extends ObjectInputStream { - - @SuppressWarnings("removal") - private MLet loader; - - /** - * Loader must be non-null; - */ - @SuppressWarnings("removal") - public MLetObjectInputStream(InputStream in, MLet loader) - throws IOException, StreamCorruptedException { - - super(in); - if (loader == null) { - throw new IllegalArgumentException("Illegal null argument to MLetObjectInputStream"); - } - this.loader = loader; - } - - private Class primitiveType(char c) { - switch(c) { - case 'B': - return Byte.TYPE; - - case 'C': - return Character.TYPE; - - case 'D': - return Double.TYPE; - - case 'F': - return Float.TYPE; - - case 'I': - return Integer.TYPE; - - case 'J': - return Long.TYPE; - - case 'S': - return Short.TYPE; - - case 'Z': - return Boolean.TYPE; - } - return null; - } - - /** - * Use the given ClassLoader rather than using the system class - */ - @Override - protected Class resolveClass(ObjectStreamClass objectstreamclass) - throws IOException, ClassNotFoundException { - - String s = objectstreamclass.getName(); - if (s.startsWith("[")) { - int i; - for (i = 1; s.charAt(i) == '['; i++); - Class class1; - if (s.charAt(i) == 'L') { - class1 = loader.loadClass(s.substring(i + 1, s.length() - 1)); - } else { - if (s.length() != i + 1) - throw new ClassNotFoundException(s); - class1 = primitiveType(s.charAt(i)); - } - int ai[] = new int[i]; - for (int j = 0; j < i; j++) - ai[j] = 0; - - return Array.newInstance(class1, ai).getClass(); - } else { - return loader.loadClass(s); - } - } - - /** - * Returns the ClassLoader being used - */ - public ClassLoader getClassLoader() { - return loader; - } -} diff --git a/src/java.management/share/classes/javax/management/loading/MLetParser.java b/src/java.management/share/classes/javax/management/loading/MLetParser.java deleted file mode 100644 index 41bb9d358784f..0000000000000 --- a/src/java.management/share/classes/javax/management/loading/MLetParser.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javax.management.loading; - -import static com.sun.jmx.defaults.JmxProperties.MLET_LOGGER; -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.lang.System.Logger.Level; - -/** - * This class is used for parsing URLs. - * - * @since 1.5 - */ -@Deprecated(since="20", forRemoval=true) -class MLetParser { - -/* - * ------------------------------------------ - * PRIVATE VARIABLES - * ------------------------------------------ - */ - - /** - * The current character - */ - private int c; - - /** - * Tag to parse. - */ - private static String tag = "mlet"; - - - /* - * ------------------------------------------ - * CONSTRUCTORS - * ------------------------------------------ - */ - - /** - * Create an MLet parser object - */ - public MLetParser() { - } - - /* - * ------------------------------------------ - * PUBLIC METHODS - * ------------------------------------------ - */ - - /** - * Scan spaces. - */ - public void skipSpace(Reader in) throws IOException { - while ((c >= 0) && ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) { - c = in.read(); - } - } - - /** - * Scan identifier - */ - public String scanIdentifier(Reader in) throws IOException { - StringBuilder buf = new StringBuilder(); - while (true) { - if (((c >= 'a') && (c <= 'z')) || - ((c >= 'A') && (c <= 'Z')) || - ((c >= '0') && (c <= '9')) || (c == '_')) { - buf.append((char)c); - c = in.read(); - } else { - return buf.toString(); - } - } - } - - /** - * Scan tag - */ - public Map scanTag(Reader in) throws IOException { - Map atts = new HashMap<>(); - skipSpace(in); - while (c >= 0 && c != '>') { - if (c == '<') - throw new IOException("Missing '>' in tag"); - String att = scanIdentifier(in); - String val = ""; - skipSpace(in); - if (c == '=') { - int quote = -1; - c = in.read(); - skipSpace(in); - if ((c == '\'') || (c == '\"')) { - quote = c; - c = in.read(); - } - StringBuilder buf = new StringBuilder(); - while ((c > 0) && - (((quote < 0) && (c != ' ') && (c != '\t') && - (c != '\n') && (c != '\r') && (c != '>')) - || ((quote >= 0) && (c != quote)))) { - buf.append((char)c); - c = in.read(); - } - if (c == quote) { - c = in.read(); - } - skipSpace(in); - val = buf.toString(); - } - atts.put(att.toLowerCase(Locale.ENGLISH), val); - skipSpace(in); - } - return atts; - } - - /** - * Scan an html file for {@literal } tags. - */ - @SuppressWarnings("removal") - public List parse(URL url) throws IOException { - // Warning Messages - String requiresTypeWarning = " tag requires type parameter."; - String requiresValueWarning = " tag requires value parameter."; - String paramOutsideWarning = " tag outside ... ."; - String requiresCodeWarning = " tag requires either code or object parameter."; - String requiresJarsWarning = " tag requires archive parameter."; - - URLConnection conn; - - conn = url.openConnection(); - Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), - UTF_8)); - - // The original URL may have been redirected - this - // sets it to whatever URL/codebase we ended up getting - // - url = conn.getURL(); - - List mlets = new ArrayList<>(); - Map atts = null; - - List types = new ArrayList<>(); - List values = new ArrayList<>(); - - // debug("parse","*** Parsing " + url ); - while(true) { - c = in.read(); - if (c == -1) - break; - if (c == '<') { - c = in.read(); - if (c == '/') { - c = in.read(); - String nm = scanIdentifier(in); - if (c != '>') - throw new IOException("Missing '>' in tag"); - if (nm.equalsIgnoreCase(tag)) { - if (atts != null) { - mlets.add(new MLetContent(url, atts, types, values)); - } - atts = null; - types = new ArrayList<>(); - values = new ArrayList<>(); - } - } else { - String nm = scanIdentifier(in); - if (nm.equalsIgnoreCase("arg")) { - Map t = scanTag(in); - String att = t.get("type"); - if (att == null) { - MLET_LOGGER.log(Level.TRACE, requiresTypeWarning); - throw new IOException(requiresTypeWarning); - } else { - if (atts != null) { - types.add(att); - } else { - MLET_LOGGER.log(Level.TRACE, paramOutsideWarning); - throw new IOException(paramOutsideWarning); - } - } - String val = t.get("value"); - if (val == null) { - MLET_LOGGER.log(Level.TRACE, requiresValueWarning); - throw new IOException(requiresValueWarning); - } else { - if (atts != null) { - values.add(val); - } else { - MLET_LOGGER.log(Level.TRACE, paramOutsideWarning); - throw new IOException(paramOutsideWarning); - } - } - } else { - if (nm.equalsIgnoreCase(tag)) { - atts = scanTag(in); - if (atts.get("code") == null && atts.get("object") == null) { - MLET_LOGGER.log(Level.TRACE, requiresCodeWarning); - throw new IOException(requiresCodeWarning); - } - if (atts.get("archive") == null) { - MLET_LOGGER.log(Level.TRACE, requiresJarsWarning); - throw new IOException(requiresJarsWarning); - } - } - } - } - } - } - in.close(); - return mlets; - } - - /** - * Parse the document pointed by the URL urlname - */ - @SuppressWarnings("removal") - public List parseURL(String urlname) throws IOException { - // Parse the document - // - URL url; - if (urlname.indexOf(':') <= 1) { - String userDir = System.getProperty("user.dir"); - String prot; - if (userDir.charAt(0) == '/' || - userDir.charAt(0) == File.separatorChar) { - prot = "file:"; - } else { - prot = "file:/"; - } - url = - new URL(prot + userDir.replace(File.separatorChar, '/') + "/"); - url = new URL(url, urlname); - } else { - url = new URL(urlname); - } - // Return list of parsed MLets - // - return parse(url); - } - -} diff --git a/src/java.management/share/classes/javax/management/loading/PrivateMLet.java b/src/java.management/share/classes/javax/management/loading/PrivateMLet.java deleted file mode 100644 index 372db255b7205..0000000000000 --- a/src/java.management/share/classes/javax/management/loading/PrivateMLet.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javax.management.loading; - -import java.net.URL; -import java.net.URLStreamHandlerFactory; - -/** - * An MLet that is not added to the {@link ClassLoaderRepository}. - * This class acts exactly like its parent class, {@link MLet}, with - * one exception. When a PrivateMLet is registered in an MBean - * server, it is not added to that MBean server's {@link - * ClassLoaderRepository}. This is true because this class implements - * the interface {@link PrivateClassLoader}. - * - * @deprecated This API is part of Management Applets (m-lets), which is a legacy feature that allows loading - * of remote MBeans. This feature is not usable without a Security Manager, which is deprecated and subject to - * removal in a future release. Consequently, this API is also deprecated and subject to removal. There is no replacement. - * - * @since 1.5 - */ -@Deprecated(since="20", forRemoval=true) -@SuppressWarnings({"serial", "removal"}) // Externalizable class w/o no-arg c'tor -public class PrivateMLet extends MLet implements PrivateClassLoader { - private static final long serialVersionUID = 2503458973393711979L; - - /** - * Constructs a new PrivateMLet for the specified URLs using the - * default delegation parent ClassLoader. The URLs will be - * searched in the order specified for classes and resources - * after first searching in the parent class loader. - * - * @param urls The URLs from which to load classes and resources. - * @param delegateToCLR True if, when a class is not found in - * either the parent ClassLoader or the URLs, the MLet should delegate - * to its containing MBeanServer's {@link ClassLoaderRepository}. - * - */ - public PrivateMLet(URL[] urls, boolean delegateToCLR) { - super(urls, delegateToCLR); - } - - /** - * Constructs a new PrivateMLet for the given URLs. The URLs will - * be searched in the order specified for classes and resources - * after first searching in the specified parent class loader. - * The parent argument will be used as the parent class loader - * for delegation. - * - * @param urls The URLs from which to load classes and resources. - * @param parent The parent class loader for delegation. - * @param delegateToCLR True if, when a class is not found in - * either the parent ClassLoader or the URLs, the MLet should delegate - * to its containing MBeanServer's {@link ClassLoaderRepository}. - * - */ - public PrivateMLet(URL[] urls, ClassLoader parent, boolean delegateToCLR) { - super(urls, parent, delegateToCLR); - } - - /** - * Constructs a new PrivateMLet for the specified URLs, parent - * class loader, and URLStreamHandlerFactory. The parent argument - * will be used as the parent class loader for delegation. The - * factory argument will be used as the stream handler factory to - * obtain protocol handlers when creating new URLs. - * - * @param urls The URLs from which to load classes and resources. - * @param parent The parent class loader for delegation. - * @param factory The URLStreamHandlerFactory to use when creating URLs. - * @param delegateToCLR True if, when a class is not found in - * either the parent ClassLoader or the URLs, the MLet should delegate - * to its containing MBeanServer's {@link ClassLoaderRepository}. - * - */ - public PrivateMLet(URL[] urls, - ClassLoader parent, - URLStreamHandlerFactory factory, - boolean delegateToCLR) { - super(urls, parent, factory, delegateToCLR); - } -} diff --git a/src/java.management/share/classes/javax/management/loading/package.html b/src/java.management/share/classes/javax/management/loading/package.html index e9d4909d69d81..0174f574ab46d 100644 --- a/src/java.management/share/classes/javax/management/loading/package.html +++ b/src/java.management/share/classes/javax/management/loading/package.html @@ -2,7 +2,7 @@ javax.management.loading package - + 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 d9469aba6b11c..50a58be99cd6c 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 a680c8f02fe72..3e0a7c7db2e30 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 c864c8d9269dd..ae88bac2414ae 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 9b77a418dd205..a75a439c011d1 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 e226cd5ece9ec..5ffb8213fbc5c 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 07bbb1f52fb3b..66bc3093c7ea6 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 176712f1595e2..5e79cc22ee712 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 e93c6d20a40e1..718ef67044e5c 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 1acdbcbe986e7..7f2a5a45a0f42 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 329140ea6bd6f..e0d1d62766cda 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 ada940d0094ac..2412c5fed215a 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 c4759676284c7..60e73788c952a 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 832be674e9885..90010dd700112 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 be576142ed45c..4e02fb64bb911 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 d4605c6072722..d51896a5d969d 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 fa5089c8e65f8..e000c824f4f40 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 32fe79fc1a8e2..0cd6bc645b6bd 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 1617e1a5fa7db..4a4034c864f0a 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 6ae22f0fcd8e5..516361b0e88ce 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 cc493bc5d6df7..29efbd5705d04 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 aabc0e3829cac..72802a59b8a16 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 3dba21fa7a048..d828c9140abe0 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 4a99ff829d5ad..64d1f8f58dc72 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 6a046b5e6b871..42975afd54d65 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 93ffbcee64be6..b755fec8fc6c6 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/SelectionCoordinator/pom.xml b/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml index cf813426bdea3..8dd8dda05af6b 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 86980e79c50fc..59d4cce7a465a 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 24533b75af02f..808a281fee4e1 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 4003013bfa6eb..21f92b3001d9a 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 789b0ee8fd8a1..3573869405708 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 bc27c79d17532..664ad35ef770b 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 c66cb8c9a2430..2ffb98774cf8c 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 4e0417884a2b5..d50f7c914ccfe 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 22540d0628be0..d5ba5b18fc143 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 a706bb6e26591..cfba9aebfce4c 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 d202691a4ab1a..8266f2cf9e1b2 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 ed33298d3e4c5..522445d897823 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 9363b05ae1f7f..772916540ff72 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 1d8e0ffa1bda8..e033a3fbc073f 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/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index 5d6bd01af420b..40d12a6145c82 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -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 @@ -32,8 +32,6 @@ class CommittedVirtualMemoryTest { public: static void test() { -#ifndef _AIX - // See JDK-8202772: temporarily disabled. Thread* thr = Thread::current(); address stack_end = thr->stack_end(); size_t stack_size = thr->stack_size(); @@ -77,7 +75,6 @@ class CommittedVirtualMemoryTest { ASSERT_TRUE(i >= 1); ASSERT_TRUE(found_stack_top); ASSERT_TRUE(found_i_addr); -#endif // !_AIX } static void check_covered_pages(address addr, size_t size, address base, size_t touch_pages, int* page_num) { diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 337484eeaecdc..470f3e7e1d461 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -507,7 +507,9 @@ TEST_VM(os, release_multi_mappings) { // ...re-reserve the middle stripes. This should work unless release silently failed. address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len); + ASSERT_EQ(p2, p_middle_stripes); + PRINT_MAPPINGS("C"); // Clean up. Release all mappings. @@ -551,26 +553,29 @@ TEST_VM(os, release_bad_ranges) { TEST_VM(os, release_one_mapping_multi_commits) { // Test that we can release an area consisting of interleaved // committed and uncommitted regions: - const size_t stripe_len = 4 * M; - const int num_stripes = 4; + const size_t stripe_len = os::vm_allocation_granularity(); + const int num_stripes = 6; const size_t total_range_len = stripe_len * num_stripes; // reserve address space... address p = reserve_one_commit_multiple(num_stripes, stripe_len); - ASSERT_NE(p, (address)NULL); PRINT_MAPPINGS("A"); + ASSERT_NE(p, (address)nullptr); - // .. release it... - ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + // // make things even more difficult by trying to reserve at the border of the region + address border = p + num_stripes * stripe_len; + address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len); PRINT_MAPPINGS("B"); - // re-reserve it. This should work unless release failed. - address p2 = (address)os::attempt_reserve_memory_at((char*)p, total_range_len); - ASSERT_EQ(p2, p); - PRINT_MAPPINGS("C"); + ASSERT_TRUE(p2 == nullptr || p2 == border); ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); - PRINT_MAPPINGS("D"); + PRINT_MAPPINGS("C"); + + if (p2 != nullptr) { + ASSERT_TRUE(os::release_memory((char*)p2, stripe_len)); + PRINT_MAPPINGS("D"); + } } static void test_show_mappings(address start, size_t size) { diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f6913a0734ddc..89d6dde8e545b 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -89,11 +89,6 @@ 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 -gc/g1/TestSkipRebuildRemsetPhase.java 8323066 linux-aarch64 ############################################################################# @@ -113,7 +108,6 @@ runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/cds/appcds/customLoader/HelloCustom_JFR.java 8241075 linux-all,windows-x64 -runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java 8323032 generic-all applications/jcstress/copy.java 8229852 linux-all diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4573c0ebb9b9d..fcd6631ceb3b6 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -246,6 +246,7 @@ tier2_compiler = \ -:hotspot_slow_compiler tier3_compiler = \ + applications/ctw/modules \ compiler/c2/ \ compiler/ciReplay/ \ compiler/compilercontrol/ \ @@ -356,7 +357,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/c2/aarch64/TestFarJump.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java index d461d56d8a390..3fe213122bda6 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/irTests/AndINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java index ad2b52392b6c3..f20c28e321db1 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 0000000000000..9aa1b62be9743 --- /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/DeMorganLawIntTests.java b/test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawIntTests.java new file mode 100644 index 0000000000000..a2d5c67965641 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawIntTests.java @@ -0,0 +1,109 @@ +/* + * 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 8322077 + * @summary Test that Ideal transformations on the De Morgan's Law perform + as expected for int. + * @library /test/lib / + * @run driver compiler.c2.irTests.DeMorganLawIntTests + */ +public class DeMorganLawIntTests { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { "test1", "test2", "test3", "test4" }) + public void runMethod() { + int a = RunInfo.getRandom().nextInt(); + int b = RunInfo.getRandom().nextInt(); + int c = RunInfo.getRandom().nextInt(); + int d = RunInfo.getRandom().nextInt(); + + int min = Integer.MIN_VALUE; + int max = Integer.MAX_VALUE; + + assertResult(0, 0, 0, 0); + assertResult(a, b, c, d); + assertResult(min, min, min, min); + assertResult(max, max, max, max); + } + + @DontCompile + public void assertResult(int a, int b, int c, int d) { + Asserts.assertEQ((~a | ~b) & (~c | ~d), test1(a, b, c, d)); + Asserts.assertEQ((~a & ~b) | (~c & ~d), test2(a, b, c, d)); + Asserts.assertEQ((~a | ~b) | (~c | ~d), test3(a, b, c, d)); + Asserts.assertEQ((~a & ~b) & (~c & ~d), test4(a, b, c, d)); + } + + // Checks (~a | ~b) & (~c | ~d) + // => ~(a & b) & ~(c & d) + // => ~((a & b) | (c & d)) + @Test + @IR(counts = { IRNode.AND , "2", + IRNode.OR , "1", + IRNode.XOR, "1", }) + public int test1(int a, int b, int c, int d) { + return (~a | ~b) & (~c | ~d); + } + + // Checks (~a & ~b) | (~c & ~d) + // => ~(a | b) | ~(c | d) + // => ~((a | b) & (c | d)) + @Test + @IR(counts = { IRNode.AND , "1", + IRNode.OR , "2", + IRNode.XOR, "1", }) + public int test2(int a, int b, int c, int d) { + return (~a & ~b) | (~c & ~d); + } + + // Checks (~a | ~b) | (~c | ~d) + // => ~(a & b) | ~(c & d) + // => ~((a & b) & (c & d)) + @Test + @IR(failOn = { IRNode.OR }) + @IR(counts = { IRNode.AND , "3", + IRNode.XOR, "1", }) + public int test3(int a, int b, int c, int d) { + return (~a | ~b) | (~c | ~d); + } + + // Checks (~a & ~b) & (~c & ~d) + // => ~(a | b) & ~(c | d) + // => ~((a | b) | (c | d)) + @Test + @IR(failOn = { IRNode.AND }) + @IR(counts = { IRNode.OR , "3", + IRNode.XOR, "1", }) + public int test4(int a, int b, int c, int d) { + return (~a & ~b) & (~c & ~d); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawLongTests.java b/test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawLongTests.java new file mode 100644 index 0000000000000..1076791b02c8d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawLongTests.java @@ -0,0 +1,109 @@ +/* + * 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 8322077 + * @summary Test that Ideal transformations on the De Morgan's Law perform + as expected for long. + * @library /test/lib / + * @run driver compiler.c2.irTests.DeMorganLawLongTests + */ +public class DeMorganLawLongTests { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { "test1", "test2", "test3", "test4" }) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + long b = RunInfo.getRandom().nextLong(); + long c = RunInfo.getRandom().nextLong(); + long d = RunInfo.getRandom().nextLong(); + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0, 0, 0); + assertResult(a, b, c, d); + assertResult(min, min, min, min); + assertResult(max, max, max, max); + } + + @DontCompile + public void assertResult(long a, long b, long c, long d) { + Asserts.assertEQ((~a | ~b) & (~c | ~d), test1(a, b, c, d)); + Asserts.assertEQ((~a & ~b) | (~c & ~d), test2(a, b, c, d)); + Asserts.assertEQ((~a | ~b) | (~c | ~d), test3(a, b, c, d)); + Asserts.assertEQ((~a & ~b) & (~c & ~d), test4(a, b, c, d)); + } + + // Checks (~a | ~b) & (~c | ~d) + // => ~(a & b) & ~(c & d) + // => ~((a & b) | (c & d)) + @Test + @IR(counts = { IRNode.AND , "2", + IRNode.OR , "1", + IRNode.XOR, "1", }) + public long test1(long a, long b, long c, long d) { + return (~a | ~b) & (~c | ~d); + } + + // Checks (~a & ~b) | (~c & ~d) + // => ~(a | b) | ~(c | d) + // => ~((a | b) & (c | d)) + @Test + @IR(counts = { IRNode.AND , "1", + IRNode.OR , "2", + IRNode.XOR, "1", }) + public long test2(long a, long b, long c, long d) { + return (~a & ~b) | (~c & ~d); + } + + // Checks (~a | ~b) | (~c | ~d) + // => ~(a & b) | ~(c & d) + // => ~((a & b) & (c & d)) + @Test + @IR(failOn = { IRNode.OR }) + @IR(counts = { IRNode.AND , "3", + IRNode.XOR, "1", }) + public long test3(long a, long b, long c, long d) { + return (~a | ~b) | (~c | ~d); + } + + // Checks (~a & ~b) & (~c & ~d) + // => ~(a | b) & ~(c | d) + // => ~((a | b) | (c | d)) + @Test + @IR(failOn = { IRNode.AND }) + @IR(counts = { IRNode.OR , "3", + IRNode.XOR, "1", }) + public long test4(long a, long b, long c, long d) { + return (~a & ~b) & (~c & ~d); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/OrINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/OrINodeIdealizationTests.java new file mode 100644 index 0000000000000..60ac26b6f45e8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/OrINodeIdealizationTests.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 8322077 + * @summary Test that Ideal transformations of OrINode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.OrINodeIdealizationTests + */ +public class OrINodeIdealizationTests { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { "test1" }) + 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, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); + } + + @DontCompile + public void assertResult(int a, int b) { + Asserts.assertEQ((~a) | (~b), test1(a, b)); + } + + // Checks (~a) | (~b) => ~(a & b) + @Test + @IR(failOn = { IRNode.OR }) + @IR(counts = { IRNode.AND, "1", + IRNode.XOR, "1" }) + public int test1(int a, int b) { + return (~a) | (~b); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/OrLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/OrLNodeIdealizationTests.java new file mode 100644 index 0000000000000..8de59bb861432 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/OrLNodeIdealizationTests.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 8322077 + * @summary Test that Ideal transformations of OrLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.OrLNodeIdealizationTests + */ +public class OrLNodeIdealizationTests { + + 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)); + } + + // Checks (~a) | (~b) => ~(a & b) + @Test + @IR(failOn = { IRNode.OR }) + @IR(counts = { IRNode.AND, "1", + IRNode.XOR, "1" }) + public long test1(long a, long b) { + return (~a) | (~b); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java index eacaa9fca8583..9b91375acb73e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.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 @@ -30,6 +30,7 @@ * @bug 8267532 * @summary check that uncommon trap is generated for unhandled catch block * @library /test/lib / + * @requires vm.opt.DeoptimizeALot != true * @run driver compiler.c2.irTests.TestPrunedExHandler */ diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java index 3b7bf23173051..b68ddfe2799ce 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/TestVectorizeTypeConversion.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java index 67c26ecbddfc3..899be4bbc9c4b 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java @@ -58,10 +58,7 @@ public static void main(String[] args) { // Mixing types of different sizes has the effect that some vectors are shorter than the type allows. @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0", IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0", - IRNode.STORE_VECTOR, ">0"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}) + IRNode.STORE_VECTOR, ">0"}) private static void testConvI2D(double[] d, int[] a) { for(int i = 0; i < d.length; i++) { d[i] = (double) (a[i]); diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java new file mode 100644 index 0000000000000..f97532abfb1fd --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java @@ -0,0 +1,65 @@ +/* + * 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 8323190 + * @summary C2 Segfaults during code generation because of unhandled SafePointScalarMerge monitor debug info. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xcomp -XX:+ReduceAllocationMerges TestInvalidLocation + */ + +public class TestInvalidLocation { + static boolean var2 = true; + static double[] var4 = new double[1]; + + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + System.out.println(test()); + } + } + + static Class0 test() { + double[] var14; + double var3; + StringBuilder var1 = new StringBuilder(); + Class0 var0 = Class1.Class1_sfield0; + synchronized (var2 ? new StringBuilder() : var1) { + var14 = var4; + for (int i0 = 0; i0 < var0.Class0_field0.length && i0 < var14.length; i0 = 1) { + var3 = var14[i0]; + } + } + return var0; + } + + static class Class0 { + double[] Class0_field0; + Class0() { + Class0_field0 = new double[] { 85.42200639495138 }; + } + } + + class Class1 { + static Class0 Class1_sfield0 = new Class0(); + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java index 0541121c127c4..ab4d8ff8bb703 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java @@ -26,6 +26,7 @@ * @bug 8289551 8302976 * @summary Verify conversion between float and the binary16 format * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch=="aarch64" + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @comment default run diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java index 38060dfb5043c..f549c1ae670a5 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java @@ -26,6 +26,7 @@ * @bug 8289551 8302976 * @summary Verify NaN sign and significand bits are preserved across conversions * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch=="aarch64" + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java index 492901f0046f0..937e17f8fca8b 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java @@ -26,6 +26,7 @@ * @bug 8302976 * @summary Verify conversion between float and the binary16 format * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch == "aarch64" + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @comment default run: diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java index b4ba578c9f260..f58cf618c1c45 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java @@ -26,6 +26,7 @@ * @bug 8302976 * @summary Verify conversion cons between float and the binary16 format * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch=="aarch64" + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @comment default run: diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 9e91268edffc3..040fe5d0222c7 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 be508bbb81e1a..67fadbc4eac31 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/irmatching/parser/hotspot/CompilePhaseBlock.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompilePhaseBlock.java index 16cc62f9c57be..b97c56a57203c 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 75d6b060cb243..49f25674dbf6c 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/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java new file mode 100644 index 0000000000000..fe873770ab44d --- /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 0000000000000..e27feb36e868c --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java @@ -0,0 +1,1355 @@ +/* + * 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 40% of the time, and subtract some margin. This ensures the shutdown has sufficient time, + // even for very slow runs. + System.out.println("Adjusted Timeout: " + Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT)); + long testTimeAllowanceDiff = (long)(Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) * 0.4) - + 20_000; + System.out.println("Time Allowance: " + testTimeAllowanceDiff); + long testTimeAllowance = System.currentTimeMillis() + testTimeAllowanceDiff; + long testHardTimeout = 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 = testTimeAllowance - System.currentTimeMillis(); + long untilTimeout = testHardTimeout - System.currentTimeMillis(); + System.out.println("ITERATION " + i + " of " + ITERATIONS_MAX + ". Test " + name + + ", time allowance: " + allowance + ", until timeout: " + untilTimeout); + + // 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() > testTimeAllowance) { + allowance = testTimeAllowance - System.currentTimeMillis(); + untilTimeout = testHardTimeout - System.currentTimeMillis(); + System.out.println("TEST PASSED: hit maximal time allownance during iteration " + i + + ", time allowance: " + allowance + ", until timeout: " + untilTimeout); + return; + } + } + } + long allowance = testTimeAllowance - System.currentTimeMillis(); + long untilTimeout = testHardTimeout - System.currentTimeMillis(); + System.out.println("TEST PASSED, time allowance: " + allowance + ", until timeout: " + untilTimeout); + } + + // 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 105b07b875874..1e48ae071069f 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 80922aeffe9cd..752c8010468a3 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 78e97f26817f8..e32da89b8cd58 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/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java new file mode 100644 index 0000000000000..97137fd1d8bc0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023, 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. + */ + +/* + * @test + * @bug 8319793 + * @summary Replacing a test with a dominating test can cause an array load to float above a range check that guards it + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:-TieredCompilation TestArrayAccessAboveRCAfterSmearingOrPredication + */ + + +public class TestArrayAccessAboveRCAfterSmearingOrPredication { + private static int field; + private static int flagField; + private static volatile int volatileField; + + public static void main(String[] args) { + float[] array = new float[100]; + for (int i = 0; i < 20_000; i++) { + testRangeCheckSmearing(array, 0, 1, true, true, true); + testRangeCheckSmearing(array, 0, 1, true, false, true); + testRangeCheckSmearing(array, 0, 1, false, false, true); + testRangeCheckSmearing(array, 0, 1, true, true, false); + testRangeCheckSmearing(array, 0, 1, true, false, false); + testRangeCheckSmearing(array, 0, 1, false, false, false); + testHelper(0); + + testLoopPredication(array, 0, 1, true, true, true); + testLoopPredication(array, 0, 1, true, false, true); + testLoopPredication(array, 0, 1, false, false, true); + testLoopPredication(array, 0, 1, true, true, false); + testLoopPredication(array, 0, 1, true, false, false); + testLoopPredication(array, 0, 1, false, false, false); + } + try { + testRangeCheckSmearing(array, Integer.MAX_VALUE, 1, false, false, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + testLoopPredication(array, Integer.MAX_VALUE, 1, false, false, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + } + + private static float testRangeCheckSmearing(float[] array, int i, int flag, boolean flag2, boolean flag3, boolean flag4) { + if (array == null) { + } + flagField = flag; + int j; + for (j = 0; j < 10; j++) { + } + for (int k = 0; k < 10; k++) { + for (int l = 0; l < 10; l++) { + } + } + testHelper(j); + float v = 0; + if (flag == 1) { + if (flag4) { + v += array[i]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + v += array[i]; + } + } else { + v += array[i]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + v += array[i]; + } + } + } + return v; + } + + private static void testHelper(int j) { + if (j == 10) { + return; + } + flagField = 0; + } + + private static float testLoopPredication(float[] array, int i, int flag, boolean flag2, boolean flag3, boolean flag4) { + i = Math.min(i, Integer.MAX_VALUE - 2); + if (array == null) { + } + flagField = flag; + int j; + for (j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + } + } + testHelper(j); + + float v = 0; + if (flag == 1) { + if (flag4) { + float dummy = array[i]; + dummy = array[i + 2]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + for (int m = 0; m < 3; m++) { + v += array[i + m]; + } + } + volatileField = 42; + } else { + float dummy = array[i]; + dummy = array[i + 2]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + for (int m = 0; m < 3; m++) { + v += array[i + m]; + } + } + volatileField = 42; + } + } + + return v; + } +} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java similarity index 52% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java rename to test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java index eeee969a2521a..e8eb1e16a7a1d 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -19,21 +19,39 @@ * 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 + * @test + * @bug 8319793 + * @summary Replacing a test with a dominating test can cause an array access CastII to float above a range check that guards it + * @run main/othervm -Xbatch -XX:-TieredCompilation TestArrayAccessCastIIAboveRC */ -public class TestGCLockerWithParallel { + +public class TestArrayAccessCastIIAboveRC { + static int N = 400; + static int iArrFld[] = new int[N]; + + static void test() { + float fArr[] = new float[N]; + int i9, i10, i12; + long lArr1[] = new long[N]; + for (i9 = 7; i9 < 43; i9++) { + try { + i10 = 7 % i9; + iArrFld[i9 + 1] = i9 / i10; + } catch (ArithmeticException a_e) { + } + for (i12 = 1; 7 > i12; i12++) + lArr1[i9 - 1] = 42; + iArrFld[i12] = 4; + fArr[i9 - 1] = 0; + } + } + public static void main(String[] args) { - String[] testArgs = {"2", "PS Old Gen"}; - TestGCLocker.main(testArgs); + for (int i = 0; i < 50_000; ++i) { + test(); + } } } diff --git a/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java new file mode 100644 index 0000000000000..28e4db334f55f --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java @@ -0,0 +1,210 @@ +/* + * 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=normal + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +/* + * @test id=fuzzer + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch -XX:PerMethodTrapLimit=0 + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +package compiler.splitif; + +public class TestSplitDivThroughPhiWithControl { + static int divisorInt = 34; + static int iFld; + static int x; + static int y; + static long divisorLong = 34L; + static long lFld; + static long lFld2; + static long lFld3; + static boolean flag; + + static int[] iArr = new int[400]; + + public static void main(String[] strArr) { + iArr[0] = 52329; + for (int i = 0; i < 10000; i++) { + flag = i % 3 == 0; // Avoid unstable if trap + divisorInt = i % 2 == 0 ? 0 : 23; // Avoid div by zero trap + divisorLong = divisorInt; // Avoid div by zero trap + try { + testIntDiv(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testIntMod(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongDiv(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongMod(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + testFuzzer(); + } + } + + static void testIntDiv() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; // AddI + int div = (sub / divisorInt); // DivI with AddI input + + if (flag) { + a = y; + } else { + a = 2; + } + // Region + + // Use StoreI with AddI input. Store needs to be split through Region in Split-If which is done together + // with AddI. + iFld = sub; + + if (a < 3) { // If that's split in Split-If + // Use of DivI -> after Split-If, DivI gets a Phi input that merges the split AddI nodes. + // -> triggers assert that we should not find pinned div nodes in cannot_split_division(). + x = div; + } + } + } + + // Same as testIntDiv() but with ModI + static void testIntMod() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; + int mod = (sub % divisorInt); + + if (flag) { + a = y; + } else { + a = 2; + } + + iFld = sub; + + if (a < 3) { + x = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Same as testIntDiv() but with DivL + static void testLongDiv() { + long a; + + for (int j = 0; j < 100; j++) { + y += 5; + long sub = j - 3; + long div = (sub / divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = div; + } + } + } + + + // Same as testIntDiv() but with ModL + static void testLongMod() { + long a; + + for (long j = 0; j < 100; j++) { + lFld2 += 5; + long sub = j - 3; + long mod = (sub % divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Original fuzzer crash + static void testFuzzer() { + int i19, i21 = 4928, i23 = 14; + for (int i = 5; i < 100; i++) { + i19 = i23; + int j = 1; + while (true) { + try { + i21 = (iArr[0] / 34); + i23 = (j % i21); + } catch (ArithmeticException a_e) { + } + iArr = iArr; + iFld = i21; + iArr[1] += 5; + if (j == 1000) { + break; + } + j++; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java b/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java deleted file mode 100644 index 63274b86e7256..0000000000000 --- a/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java +++ /dev/null @@ -1,64 +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. 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 8316533 - * @summary Oop of abstract class A with no subclass is subtype checked after null-check - * @run driver compiler.types.TestSubTypeOfAbstractClass - */ - -/** - * @test - * @bug 8316533 - * @summary Oop of abstract class A is subtype checked after null-check - * @requires vm.compiler2.enabled - * @run main/othervm -XX:CompileCommand=compileonly,*A::test - * -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode - * compiler.types.TestSubTypeOfAbstractClass - */ - -package compiler.types; - -public class TestSubTypeOfAbstractClass { - - abstract class A { - public static A get_null() { - return null; - } - - public static boolean test() { - // NullCheck -> CastPP with type A:NotNull - // But A is abstract with no subclass, hence this type is impossible - return get_null() instanceof A; - } - } - - public static void main(String[] args) { - for (int i = 0; i < 10_000; i++ ) { - A.test(); - } - } -} diff --git a/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java b/test/hotspot/jtreg/compiler/vectorization/TestBufferVectorization.java index 889cc68f876b6..76251ba99c8c3 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/compiler/vectorization/runner/ArrayTypeConvertTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java index 7956fa5f61863..60d3c05dab60b 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java @@ -143,9 +143,6 @@ public float[] convertIntToFloat() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}, counts = {IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0"}) public double[] convertIntToDouble() { double[] res = new double[SIZE]; @@ -233,9 +230,6 @@ public int[] convertFloatToInt() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}, counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"}) public long[] convertFloatToLong() { long[] res = new long[SIZE]; @@ -317,9 +311,6 @@ public char[] convertDoubleToChar() { // ---------------- Convert Between F & D ---------------- @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}, counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"}) public double[] convertFloatToDouble() { double[] res = new double[SIZE]; diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java index 0f758be4ed0c7..a3fcdbaa9b008 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. 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 @@ -237,6 +238,17 @@ public double[] vectorMax() { return res; } + @Test + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, + counts = {IRNode.MAX_VD, ">0"}) + public double[] vectorMax_8322090() { + double[] res = new double[SIZE]; + for (int i = 0; i < SIZE; i++) { + res[i] = Math.max(d[i], d[i]); + } + return res; + } + @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, counts = {IRNode.MIN_VD, ">0"}) diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index fbea62f81f8d5..5b7f96112b901 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/g1/TestHumongousAllocConcurrentStart.java b/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.java index 9631fd1855ce1..0d932ef50d4b9 100644 --- a/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.java +++ b/test/hotspot/jtreg/gc/g1/TestHumongousAllocConcurrentStart.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 @@ -28,6 +28,7 @@ * @bug 7168848 * @summary G1: humongous object allocations should initiate marking cycles when necessary * @requires vm.gc.G1 + * @requires vm.flagless * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -45,7 +46,7 @@ public class TestHumongousAllocConcurrentStart { private static final int initiatingHeapOccupancyPercent = 50; // % public static void main(String[] args) throws Exception { - OutputAnalyzer output = ProcessTools.executeTestJava( + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( "-XX:+UseG1GC", "-Xms" + heapSize + "m", "-Xmx" + heapSize + "m", diff --git a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java index f7f768c9d7dfd..1dc64bf625510 100644 --- a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java +++ b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java @@ -45,7 +45,7 @@ public static void main(String[] args) throws Exception { "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "-XX:G1MixedGCLiveThresholdPercent=20", + "-XX:G1MixedGCLiveThresholdPercent=0", "-Xlog:gc+marking=debug,gc+phases=debug,gc+remset+tracking=trace", "-Xms10M", "-Xmx10M", @@ -58,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/stress/gclocker/TestGCLocker.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java deleted file mode 100644 index 36b9a59fde66a..0000000000000 --- 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 586fdc798817f..0000000000000 --- 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/runtime/cds/appcds/JarBuilder.java b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java index b9c2063f3e7e1..ef13a0a94141b 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 0000000000000..9e7579a34fd3e --- /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/test-classes/DefineModuleApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java new file mode 100644 index 0000000000000..fad62598cc73b --- /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 0000000000000..7558b8b2c82a5 --- /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 53de474d9cd41..aeb5696830df4 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java @@ -345,20 +345,26 @@ public static void runWithJarPath(String... extraRuntimeArgs) throws Exception { .shouldNotContain(OPTIMIZE_ENABLED) .shouldContain(MAP_FAILED); }); - // 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); + + // 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/gc/stress/gclocker/libTestGCLocker.c b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm similarity index 67% rename from test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c rename to test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm index 2ac2064775c26..24c53f2032da9 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, 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,17 +19,25 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. + * */ +/* + * This is a non-abstract class with an abstract method. + * + */ +super public class AbstractMethodClass + extends java/lang/Object + version 51:0 // Java 7 version +{ + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } -#include + public abstract Method "abstractM":"()V"; -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); } diff --git a/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java b/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java new file mode 100644 index 0000000000000..2384f6d5aef15 --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.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. + * + */ + +/* + * @test + * @bug 8323243 + * @summary Test that invocation of an abstract method from JNI works correctly + * @compile AbstractMethodClass.jasm + * @run main/othervm/native TestJNIAbstractMethod + */ + +/** + * We are testing invocation of an abstract method from JNI - which should + * simply result in throwning AbstractMethodError. To invoke an abstract method + * we must have an instance method (as abstract static methods are illegal), + * but instantiating an abstract class is also illegal at the Java language + * level, so we have to use a custom jasm class that contains an abstract method + * declaration, but which is not itself declared as an abstract class. + */ +public class TestJNIAbstractMethod { + + // Invokes an abstract method from JNI and throws AbstractMethodError. + private static native void invokeAbstractM(Class AMclass, + AbstractMethodClass receiver); + + static { + System.loadLibrary("JNIAbstractMethod"); + } + + public static void main(String[] args) { + AbstractMethodClass obj = new AbstractMethodClass(); + try { + System.out.println("Attempting direct invocation via Java"); + obj.abstractM(); + throw new RuntimeException("Did not get AbstractMethodError from Java!"); + } catch (AbstractMethodError expected) { + System.out.println("ok - got expected exception: " + expected); + } + try { + System.out.println("Attempting direct invocation via JNI"); + invokeAbstractM(obj.getClass(), obj); + throw new RuntimeException("Did not get AbstractMethodError from JNI!"); + } catch (AbstractMethodError expected) { + System.out.println("ok - got expected exception: " + expected); + } + } +} diff --git a/test/jdk/java/util/zip/ZipFile/Available.java b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c similarity index 55% rename from test/jdk/java/util/zip/ZipFile/Available.java rename to test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c index 364a3b0243944..35a28f7029ac3 100644 --- a/test/jdk/java/util/zip/ZipFile/Available.java +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c @@ -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 @@ -19,19 +19,25 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. + * */ +#include +#include +#include + +JNIEXPORT void JNICALL Java_TestJNIAbstractMethod_invokeAbstractM(JNIEnv* env, + jclass this_cls, + jclass target_cls, + jobject receiver) { + + jmethodID mid = (*env)->GetMethodID(env, target_cls, "abstractM", "()V"); + if (mid == NULL) { + fprintf(stderr, "Error looking up method abstractM\n"); + (*env)->ExceptionDescribe(env); + exit(1); + } -import java.util.zip.*; -import java.io.File; + printf("Invoking abstract method ...\n"); + (*env)->CallVoidMethod(env, receiver, mid); // Should raise exception -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"); - } - } } diff --git a/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java b/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java index e88bc025e8c77..9fc4fdcaef5d6 100644 --- a/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java +++ b/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java @@ -61,12 +61,11 @@ public static class InflateMonitorsTest { static WhiteBox wb = WhiteBox.getWhiteBox(); public static Object obj; - public static void main(String args[]) { + public static void main(String args[]) throws Exception { obj = new Object(); synchronized (obj) { - // HotSpot implementation detail: asking for the hash code - // when the object is locked causes monitor inflation. - if (obj.hashCode() == 0xBAD) System.out.println("!"); + // The current implementation of notify-wait requires inflation. + obj.wait(1); Asserts.assertEQ(wb.isMonitorInflated(obj), true, "Monitor should be inflated."); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java index 7fe5abb800fd2..2243a1d37b6ba 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; @@ -223,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++) { @@ -250,6 +263,10 @@ 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); diff --git a/test/hotspot/jtreg/testlibrary/ctw/Makefile b/test/hotspot/jtreg/testlibrary/ctw/Makefile index 5ba3bbb659a42..b67500d0c5e0b 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 99de3c1510ca7..0000000000000 --- 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 2bdd2540f08a5..0000000000000 --- 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/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java new file mode 100644 index 0000000000000..442f13f49273d --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java @@ -0,0 +1,201 @@ +/* + * 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.catalog; + +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.SAXException; + +import javax.xml.catalog.CatalogFeatures; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.SchemaFactory; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.catalog.CatalogManager.catalogResolver; +import javax.xml.catalog.CatalogResolver; +import javax.xml.validation.Validator; +import org.testng.annotations.Test; + +/* + * @test + * @bug 8323571 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng common.catalog.NullIdTest + * @summary Verifies null values are handled properly in the source resolution + * process. + */ +public class NullIdTest { + private static final Map SCHEMAS; + // Source Level JDK 8 + static { + Map map = new HashMap<>(); + map.put("https://schemas.opentest4j.org/reporting/events/0.1.0", "events.xsd"); + map.put("https://schemas.opentest4j.org/reporting/core/0.1.0", "core.xsd"); + SCHEMAS = Collections.unmodifiableMap(map); + } + + /* + * Verifies that the source resolution process recognizes the custom InputSource + * correctly even though the public and system IDs are null. + */ + @Test + public void test() throws Exception { + String xml = ""; + validate(new StreamSource(new StringReader(xml))); + System.out.println("Successfully validated"); + } + + private static void validate(Source source) throws SAXException, IOException { + SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + Validator validator = schemaFactory.newSchema().newValidator(); + validator.setResourceResolver(createResourceResolver()); + validator.validate(source); + } + + private static LSResourceResolver createResourceResolver() { + return (type, namespaceURI, publicId, systemId, baseURI) -> { + if (namespaceURI != null) { + if (SCHEMAS.containsKey(namespaceURI)) { + CustomLSInputImpl input = new CustomLSInputImpl(); + input.setPublicId(publicId); + String schema = SCHEMAS.get(namespaceURI); + input.setSystemId(requireNonNull(NullIdTest.class.getResource(schema)).toExternalForm()); + input.setBaseURI(baseURI); + InputStream stream = NullIdTest.class.getResourceAsStream(schema); + input.setCharacterStream(new InputStreamReader(requireNonNull(stream))); + return input; + } + } + if (systemId != null) { + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.RESOLVE, "continue") + .build(); + CatalogResolver catalogResolver = catalogResolver(features); + return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI); + } + return null; + }; + } + + static class CustomLSInputImpl implements LSInput { + + private Reader characterStream; + private InputStream byteStream; + private String stringData; + private String systemId; + private String publicId; + private String baseURI; + private String encoding; + private boolean certifiedText; + + @Override + public Reader getCharacterStream() { + return characterStream; + } + + @Override + public void setCharacterStream(Reader characterStream) { + this.characterStream = characterStream; + } + + @Override + public InputStream getByteStream() { + return byteStream; + } + + @Override + public void setByteStream(InputStream byteStream) { + this.byteStream = byteStream; + } + + @Override + public String getStringData() { + return stringData; + } + + @Override + public void setStringData(String stringData) { + this.stringData = stringData; + } + + @Override + public String getSystemId() { + return systemId; + } + + @Override + public void setSystemId(String systemId) { + this.systemId = systemId; + } + + @Override + public String getPublicId() { + return publicId; + } + + @Override + public void setPublicId(String publicId) { + this.publicId = publicId; + } + + @Override + public String getBaseURI() { + return baseURI; + } + + @Override + public void setBaseURI(String baseURI) { + this.baseURI = baseURI; + } + + @Override + public String getEncoding() { + return encoding; + } + + @Override + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + @Override + public boolean getCertifiedText() { + return certifiedText; + } + + @Override + public void setCertifiedText(boolean certifiedText) { + this.certifiedText = certifiedText; + } + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd new file mode 100644 index 0000000000000..41b0de3425be5 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd new file mode 100644 index 0000000000000..56d5a43121193 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jdk/ProblemList-generational-zgc.txt b/test/jdk/ProblemList-generational-zgc.txt index d6a6f63c6a5e8..9fa9874d20c64 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 df7edd2cf7d08..9fae070e25d1f 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 b2354126c06bd..4db764822c18f 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -624,7 +624,6 @@ sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 gene sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le -sun/security/pkcs11/Provider/MultipleLogins.sh 8319128 linux-aarch64 ############################################################################ diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java index 27b72b5cf7ca2..22c5c89b57be2 100644 --- a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java +++ b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.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 @@ -26,7 +26,9 @@ * @bug 8297878 * @summary Key Encapsulation Mechanism API * @library /test/lib + * @build java.base/com.sun.crypto.provider.EvenKEMImpl * @modules java.base/com.sun.crypto.provider + * @run main/othervm Compliance */ import jdk.test.lib.Asserts; import jdk.test.lib.Utils; @@ -45,18 +47,19 @@ import com.sun.crypto.provider.DHKEM; +import static com.sun.crypto.provider.EvenKEMImpl.isEven; + public class Compliance { public static void main(String[] args) throws Exception { basic(); conform(); determined(); - try { - Security.insertProviderAt(new ProviderImpl(), 1); - delayed(); - } finally { - Security.removeProvider("XP"); - } + // Patch an alternate DHKEM in SunEC which is ahead of SunJCE + // in security provider listing. + Security.getProvider("SunEC") + .put("KEM.DHKEM", "com.sun.crypto.provider.EvenKEMImpl"); + delayed(); } // Encapsulated conformance checks @@ -220,34 +223,6 @@ static byte[] calcDetermined(long seed) throws Exception { return enc2; } - public static class ProviderImpl extends Provider { - ProviderImpl() { - super("XP", "1", "XP"); - put("KEM.DHKEM", "Compliance$KEMImpl"); - } - } - - static boolean isEven(Key k) { - return Arrays.hashCode(k.getEncoded()) % 2 == 0; - } - - public static class KEMImpl extends DHKEM { - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewEncapsulator(pk, spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewDecapsulator(sk, spec); - } - } - // Ensure delayed provider selection static void delayed() throws Exception { KeyPairGenerator g = KeyPairGenerator.getInstance("X25519"); @@ -266,7 +241,7 @@ static void delayed() throws Exception { KEM.Encapsulator eodd = kem.newEncapsulator(odd); KEM.Encapsulator eeven = kem.newEncapsulator(even); Asserts.assertEQ(eodd.providerName(), "SunJCE"); - Asserts.assertEQ(eeven.providerName(), "XP"); + Asserts.assertEQ(eeven.providerName(), "SunEC"); } static ECPublicKey badECKey() { diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java new file mode 100644 index 0000000000000..dc478c25954a8 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.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. + */ +package com.sun.crypto.provider; + +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; + +// The alternate DHKEM implementation used by the Compliance.java test. +public class EvenKEMImpl extends DHKEM { + + public static boolean isEven(Key k) { + return Arrays.hashCode(k.getEncoded()) % 2 == 0; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewEncapsulator(pk, spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey sk, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewDecapsulator(sk, spec); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java b/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java index c74d800860e6a..8197fd436e759 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @summary Test to stress directory listings * @library /test/lib - * @run testng/othervm/timeout=180 StressDirListings + * @run testng/othervm/timeout=180 -Dsun.net.httpserver.nodelay=true StressDirListings */ import java.io.IOException; diff --git a/test/jdk/java/awt/FullScreen/SetFullScreenTest.java b/test/jdk/java/awt/FullScreen/SetFullScreenTest.java new file mode 100644 index 0000000000000..316bc2f64fa3e --- /dev/null +++ b/test/jdk/java/awt/FullScreen/SetFullScreenTest.java @@ -0,0 +1,89 @@ +/* + * 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.awt.Color; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Robot; +import jtreg.SkippedException; + +import static java.awt.EventQueue.invokeAndWait; + +/* + * @test + * @key headful + * @bug 8312518 + * @library /test/lib + * @summary Setting fullscreen window using setFullScreenWindow() shows up + * as black screen on newer macOS versions (13 & 14). + */ + +public class SetFullScreenTest { + private static Frame frame; + private static GraphicsDevice gd; + private static Robot robot; + private static volatile int width; + private static volatile int height; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + invokeAndWait(() -> { + gd = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice(); + if (!gd.isFullScreenSupported()) { + throw new SkippedException("Full Screen mode not supported"); + } + }); + + invokeAndWait(() -> { + frame = new Frame("Test FullScreen mode"); + frame.setBackground(Color.RED); + frame.setSize(100, 100); + frame.setLocation(10, 10); + frame.setVisible(true); + }); + robot.delay(1000); + + invokeAndWait(() -> gd.setFullScreenWindow(frame)); + robot.waitForIdle(); + robot.delay(300); + + invokeAndWait(() -> { + width = gd.getFullScreenWindow().getWidth(); + height = gd.getFullScreenWindow().getHeight(); + }); + + if (!robot.getPixelColor(width / 2, height / 2).equals(Color.RED)) { + System.err.println("Actual color: " + robot.getPixelColor(width / 2, height / 2) + + " Expected color: " + Color.RED); + throw new RuntimeException("Test Failed! Window not in full screen mode"); + } + } finally { + if (frame != null) { + frame.dispose(); + } + } + } +} diff --git a/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java b/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java index 452054a8f110b..5bfadc6fbe7cd 100644 --- a/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java +++ b/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.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 @@ -94,9 +94,13 @@ public static void main(String[] args) throws Exception { robot.mouseMove(MOUSE_POS3, MOUSE_POS3); syncLocationToWindowManager(); } finally { - SwingUtilities.invokeLater(() -> { - frame1.dispose(); - frame2.dispose(); + SwingUtilities.invokeAndWait(() -> { + if (frame1 != null) { + frame1.dispose(); + } + if (frame2 != null) { + frame2.dispose(); + } }); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java b/test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java similarity index 50% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java rename to test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java index 302bd203277e1..c67f52263c0f3 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java +++ b/test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. 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,31 +22,29 @@ * questions. */ -package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; +import java.awt.color.ColorSpace; +import java.util.Arrays; /** - * 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 + * @test + * @bug 4760025 + * @summary Verifies sRGB conversions to and from CIE XYZ */ -class WriterThread { - private LoggedMethod loggedMethod = LoggedMethod.DONT_CARE; - - public static boolean isWriterThreadLine(String line) { - return line.startsWith(" 0.0001f || inv[2] != 0) { + System.err.println("Expected color:\t" + Arrays.toString(rgb)); + System.err.println("XYZ color:\t\t" + Arrays.toString(xyz)); + System.err.println("Actual color:\t" + Arrays.toString(inv)); + throw new Error("Wrong color"); + } } - return restoredLoggedMethod; } } diff --git a/test/jdk/java/awt/print/PageFormat/CustomPaper.java b/test/jdk/java/awt/print/PageFormat/CustomPaper.java index 1976a20c01f12..7af689176d86a 100644 --- a/test/jdk/java/awt/print/PageFormat/CustomPaper.java +++ b/test/jdk/java/awt/print/PageFormat/CustomPaper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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,224 +21,162 @@ * questions. */ +import java.awt.BasicStroke; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import jtreg.SkippedException; + /* * @test * @bug 4355514 + * @key printer + * @summary Prints a rectangle to show the imageable area of a + * 12in x 14in custom paper size. + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual CustomPaper 4355514 + */ + +/* + * @test * @bug 4385157 * @key printer * @summary Prints a rectangle to show the imageable area of a * 12in x 14in custom paper size. - * @run main/manual CustomPaper + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual CustomPaper 4385157 */ +public class CustomPaper implements Pageable, Printable { -import java.awt.*; -import java.awt.print.*; -import java.awt.geom.*; - -public class CustomPaper implements Pageable, Printable{ - - private static double PIXELS_PER_INCH = 72.0; - - private PrinterJob printerJob; - private PageFormat pageFormat; - - CustomPaper(){ - printerJob = PrinterJob.getPrinterJob(); - createPageFormat(); - } - - private void createPageFormat(){ - pageFormat = new PageFormat(); - Paper p = new Paper(); - double width = 12.0*PIXELS_PER_INCH; - double height = 14.0*PIXELS_PER_INCH; - double ix = PIXELS_PER_INCH; - double iy = PIXELS_PER_INCH; - double iwidth = width - 2.0*PIXELS_PER_INCH; - double iheight = height - 2.0*PIXELS_PER_INCH; - p.setSize(width, height); - p.setImageableArea(ix, iy, iwidth, iheight); - pageFormat.setPaper(p); - } - - public Printable getPrintable(int index){ - return this; - } - - public PageFormat getPageFormat(int index){ - return pageFormat; - } - - public int getNumberOfPages(){ - return 1; - } - - public void print(){ - if(printerJob.printDialog()) - { - try{ - printerJob.setPageable(this); - printerJob.print(); - }catch(Exception e){e.printStackTrace();} - } + private static final double PIXELS_PER_INCH = 72.0; + + private final PrinterJob printerJob; + private PageFormat pageFormat; - } - - public int print(Graphics g, PageFormat pf, int pageIndex){ - if(pageIndex == 0){ - Graphics2D g2 = (Graphics2D)g; - Rectangle2D r = new Rectangle2D.Double(pf.getImageableX(), - pf.getImageableY(), - pf.getImageableWidth(), - pf.getImageableHeight()); - g2.setStroke(new BasicStroke(3.0f)); - g2.draw(r); - return PAGE_EXISTS; - }else{ - return NO_SUCH_PAGE; + CustomPaper() { + printerJob = PrinterJob.getPrinterJob(); + createPageFormat(); } - } - - public static void main(String[] args){ - - String[] instructions = - { - "You must have a printer that supports custom paper size of ", - "at least 12 x 14 inches to perform this test. It requires", - "user interaction and you must have a 12 x 14 inch paper available.", - " ", - "To test bug ID 4385157, click OK on print dialog box to print.", - " ", - "To test bug ID 4355514, select the printer in the Print Setup dialog and add a ", - "custom paper size under Printer properties' Paper selection menu. ", - "Set the dimension to width=12 inches and height=14 inches.", - "Select this custom paper size before proceeding to print.", - " ", - "Visual inspection of the one-page printout is needed. A passing", - "test will print a rectangle of the imageable area which is approximately", - "10 x 12 inches.", - }; - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - CustomPaper pt = new CustomPaper(); - pt.print(); - //System.exit (0); - } + private void createPageFormat() { + pageFormat = new PageFormat(); + Paper p = new Paper(); + double width = 12.0 * PIXELS_PER_INCH; + double height = 14.0 * PIXELS_PER_INCH; + double iwidth = width - 2.0 * PIXELS_PER_INCH; + double iheight = height - 2.0 * PIXELS_PER_INCH; + p.setSize(width, height); + p.setImageableArea(PIXELS_PER_INCH, PIXELS_PER_INCH, iwidth, iheight); + pageFormat.setPaper(p); + } -} + @Override + public Printable getPrintable(int index) { + return this; + } + @Override + public PageFormat getPageFormat(int index) { + return pageFormat; + } -class Sysout { - private static TestDialog dialog; + @Override + public int getNumberOfPages() { + return 1; + } - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); + private void print() throws PrinterException { + if (printerJob.printDialog()) { + printerJob.setPageable(this); + printerJob.print(); + } else { + PassFailJFrame.forceFail("Printing canceled by user"); + } } - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); + @Override + public int print(Graphics g, PageFormat pf, int pageIndex) { + if (pageIndex == 0) { + Graphics2D g2 = (Graphics2D) g; + Rectangle2D r = new Rectangle2D.Double(pf.getImageableX(), + pf.getImageableY(), + pf.getImageableWidth(), + pf.getImageableHeight()); + g2.setStroke(new BasicStroke(3.0f)); + g2.draw(r); + return PAGE_EXISTS; + } else { + return NO_SUCH_PAGE; + } } + private static final String TOP = """ + You must have a printer that supports custom paper size of + at least 12 x 14 inches to perform this test. It requires + user interaction and you must have a 12 x 14 inch paper available. - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } + """; + private static final String BOTTOM = """ - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } + Visual inspection of the one-page printout is needed. A passing + test will print a rectangle of the imageable area which is + approximately 10 x 12 inches. + """; -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } + private static final String INSTRUCTIONS_4355514 = """ + Select the printer in the Print Setup dialog and add a custom + paper size under 'Printer properties' Paper selection menu. + Set the dimension to width=12 inches and height=14 inches. + Select this custom paper size before proceeding to print. + """; + + private static final String INSTRUCTIONS_4385157 = """ + Click OK on print dialog box to print. + """; + + public static void main(String[] args) throws Exception { + String instructions; + + if (PrinterJob.lookupPrintServices().length == 0) { + throw new SkippedException("Printer not configured or available." + + " Test cannot continue."); + } - }// TestDialog class + if (args.length != 1) { + throw new RuntimeException("Select a test by passing 4355514 or 4385157"); + } + + instructions = switch (args[0]) { + case "4355514" -> TOP + INSTRUCTIONS_4355514 + BOTTOM; + case "4385157" -> TOP + INSTRUCTIONS_4385157 + BOTTOM; + default -> throw new RuntimeException("Unknown bugid " + args[0] + "." + + "Valid values: 4355514 or 4385157"); + }; + + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("CustomPaper Test Instructions") + .instructions(instructions) + .testTimeOut(5) + .rows((int) instructions.lines().count() + 1) + .columns(45) + .build(); + + CustomPaper pt = new CustomPaper(); + pt.print(); + passFailJFrame.awaitAndCheck(); + } +} diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index f4048aaa68a08..2aa398468cc9f 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/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index d56f44388a4bb..b749c96ac5421 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -164,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/TestScope.java b/test/jdk/java/foreign/TestScope.java index 337dce7d0ca0b..b7bcc4d373cc0 100644 --- a/test/jdk/java/foreign/TestScope.java +++ b/test/jdk/java/foreign/TestScope.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 @@ -31,8 +31,11 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.HexFormat; +import java.util.stream.LongStream; import static org.testng.Assert.*; @@ -108,6 +111,30 @@ public void testSameLookupScope() { testDerivedBufferScope(segment1.reinterpret(10)); } + @Test + public void testZeroedOfAuto() { + testZeroed(Arena.ofAuto()); + } + + @Test + public void testZeroedGlobal() { + testZeroed(Arena.global()); + } + + @Test + public void testZeroedOfConfined() { + try (Arena arena = Arena.ofConfined()) { + testZeroed(arena); + } + } + + @Test + public void testZeroedOfShared() { + try (Arena arena = Arena.ofShared()) { + testZeroed(arena); + } + } + void testDerivedBufferScope(MemorySegment segment) { ByteBuffer buffer = segment.asByteBuffer(); MemorySegment.Scope expectedScope = segment.scope(); @@ -119,4 +146,14 @@ void testDerivedBufferScope(MemorySegment segment) { IntBuffer view = buffer.asIntBuffer(); assertEquals(expectedScope, MemorySegment.ofBuffer(view).scope()); } + + private static final MemorySegment ZEROED_MEMORY = MemorySegment.ofArray(new byte[8102]); + + void testZeroed(Arena arena) { + long byteSize = ZEROED_MEMORY.byteSize(); + var segment = arena.allocate(byteSize, Long.BYTES); + long mismatch = ZEROED_MEMORY.mismatch(segment); + assertEquals(mismatch, -1); + } + } diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java index 70223c00c008d..d680d23414570 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 0e0c49320da07..87418f39d90af 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; @@ -189,6 +191,81 @@ public void testAllocatorAllocateFromHeapSegment() { } } + // 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 414cd0a8451d9..88636bf5420ce 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -145,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 94b49eb7e594c..44ecd12ba5ebd 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)); diff --git a/test/jdk/java/foreign/UpcallTestHelper.java b/test/jdk/java/foreign/UpcallTestHelper.java index bbc01959ccdaf..8adf5580f514c 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 @@ -29,8 +29,9 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; public class UpcallTestHelper extends NativeTestHelper { @@ -50,16 +51,18 @@ public OutputAnalyzer runInNewProcess(Class target, boolean useSpec, List[] 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"); @@ -70,7 +85,33 @@ public static void main(String... args) throws ReflectiveOperationException { AnInterface.class, LocalMap.class, AnEnum.class, - AnotherEnum.class)) { + AnotherEnum.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()); } @@ -107,7 +148,102 @@ 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{}; } + +// 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/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java index 1790ef5eeac5b..e00cf89fb8cba 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -26,30 +26,44 @@ * @bug 8322818 * @summary Stress test Thread.getStackTrace on a virtual thread that is pinned * @requires vm.debug != true - * @run main GetStackTraceALotWhenPinned 25000 + * @modules java.base/java.lang:+open + * @library /test/lib + * @run main/othervm GetStackTraceALotWhenPinned 500000 */ /* * @test * @requires vm.debug == true - * @run main/timeout=300 GetStackTraceALotWhenPinned 10000 + * @modules java.base/java.lang:+open + * @library /test/lib + * @run main/othervm/timeout=300 GetStackTraceALotWhenPinned 200000 */ import java.time.Instant; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; +import jdk.test.lib.thread.VThreadRunner; public class GetStackTraceALotWhenPinned { public static void main(String[] args) throws Exception { - var counter = new AtomicInteger(Integer.parseInt(args[0])); + // need at least two carrier threads when main thread is a virtual thread + if (Thread.currentThread().isVirtual()) { + VThreadRunner.ensureParallelism(2); + } + + int iterations = Integer.parseInt(args[0]); + var barrier = new Barrier(2); // 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) { + for (int i = 0; i < iterations; i++) { + // wait for main thread to arrive + barrier.await(); + Thread.yield(); synchronized (GetStackTraceALotWhenPinned.class) { if (timed) { @@ -63,14 +77,47 @@ public static void main(String[] args) throws Exception { }); long lastTimestamp = System.currentTimeMillis(); - while (thread.isAlive()) { + for (int i = 0; i < iterations; i++) { + // wait for virtual thread to arrive + barrier.await(); + thread.getStackTrace(); LockSupport.unpark(thread); + long currentTime = System.currentTimeMillis(); if ((currentTime - lastTimestamp) > 500) { - System.out.format("%s %d remaining ...%n", Instant.now(), counter.get()); + System.out.format("%s %d remaining ...%n", Instant.now(), (iterations - i)); lastTimestamp = currentTime; } } } + + /** + * Alow threads wait for each other to reach a common barrier point. This class does + * not park threads that are waiting for the barrier to trip, instead it spins. This + * makes it suitable for tests that use LockSupport.park or Thread.yield. + */ + private static class Barrier { + private final int parties; + private final AtomicInteger count; + private volatile int generation; + + Barrier(int parties) { + this.parties = parties; + this.count = new AtomicInteger(parties); + } + + void await() { + int g = generation; + if (count.decrementAndGet() == 0) { + count.set(parties); + generation = g + 1; + } else { + while (generation == g) { + Thread.onSpinWait(); + } + } + } + + } } diff --git a/test/jdk/java/math/BigInteger/HashCode.java b/test/jdk/java/math/BigInteger/HashCode.java new file mode 100644 index 0000000000000..ecd3b8f368e4b --- /dev/null +++ b/test/jdk/java/math/BigInteger/HashCode.java @@ -0,0 +1,74 @@ +/* + * 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 java.math.BigInteger; + +/* + * @test + * @bug 8310813 + * @summary Check hashCode implementation against reference values + */ +public class HashCode { + + // This test guards against inadvertent changes to BigInteger.hashCode, + // by checking generated hashCode values against reference values + // captured immediately before 8310813 + + public static void main(String[] args) { + equals( 0, BigInteger.ZERO); + equals( 1, BigInteger.ONE); + equals( 2, BigInteger.TWO); + equals( 10, BigInteger.TEN); + equals( -128, BigInteger.valueOf(Byte.MIN_VALUE)); + equals( 127, BigInteger.valueOf(Byte.MAX_VALUE)); + equals( -32768, BigInteger.valueOf(Short.MIN_VALUE)); + equals( 32767, BigInteger.valueOf(Short.MAX_VALUE)); + equals( 0, BigInteger.valueOf(Character.MIN_VALUE)); + equals( 65535, BigInteger.valueOf(Character.MAX_VALUE)); + equals(-2147483648, BigInteger.valueOf(Integer.MIN_VALUE)); + equals( 2147483647, BigInteger.valueOf(Integer.MAX_VALUE)); + equals(-2147483648, BigInteger.valueOf(Long.MIN_VALUE)); + equals( 2147483616, BigInteger.valueOf(Long.MAX_VALUE)); + equals( -1, BigInteger.valueOf(-1)); + + // a 37-byte negative number, generated at random + equals( 1428257188, new BigInteger(""" + -5573526435790097067262357965922443376770234990700620666883\ + 2705705469477701887396205062479""")); + // a 123-byte positive number, generated at random + equals( -412503667, new BigInteger(""" + 13093241912251296135908856604398494061635394768699286753760\ + 22827291528069076557720973813183142494646514532475660126948\ + 43316474303725664231917408569680292008962577772928370936861\ + 12952691245923210726443405774197400117701581498597123145452\ + 15111774818054200162634242662445757757255702394598235971294\ + 50""")); + } + + private static void equals(int expectedHashCode, BigInteger i) { + int actualHashCode = i.hashCode(); + if (expectedHashCode != actualHashCode) + throw new AssertionError("%s: expectedHashCode=%s, actual=%s" + .formatted(i, expectedHashCode, actualHashCode)); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProviders.java b/test/jdk/java/util/Locale/LocaleProviders.java index c4acb0689b1bb..556409fb65007 100644 --- a/test/jdk/java/util/Locale/LocaleProviders.java +++ b/test/jdk/java/util/Locale/LocaleProviders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,10 @@ import java.util.logging.StreamHandler; import java.util.spi.*; import java.util.stream.IntStream; +import java.util.stream.Stream; + +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; import sun.util.locale.provider.LocaleProviderAdapter; import static java.util.logging.LogManager.*; @@ -447,7 +451,8 @@ static void bug8248695Test() { } } - // Run only if the platform locale is en-GB + // Run only if the underlying platform locale is en-GB + // (Setting the java locale via command line properties does not substitute this) static void bug8257964Test() { var defLoc = Locale.getDefault(Locale.Category.FORMAT); var type = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.UK) @@ -476,4 +481,30 @@ static void bug8257964Test() { "provider is not HOST: " + type); } } + + /* Method is used by the LocaleProviders* related tests to launch a + * LocaleProviders test method with the appropriate LocaleProvider (e.g. CLDR, + * COMPAT, ETC.) + */ + static void test(String prefList, String methodName, String... params) throws Throwable { + + List command = List.of( + "-ea", "-esa", + "-cp", Utils.TEST_CLASS_PATH, + // Required for LocaleProvidersLogger + "-Djava.util.logging.config.class=LocaleProviders$LogConfig", + "-Djava.locale.providers=" + prefList, + "--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED", + "LocaleProviders", methodName); + + // Build process with arguments, if required by the method + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Stream.concat(command.stream(), Stream.of(params)).toList()); + + // Evaluate process status + int exitCode = ProcessTools.executeCommand(pb).getExitValue(); + if (exitCode != 0) { + throw new RuntimeException("Unexpected exit code: " + exitCode); + } + } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersCalendar.java b/test/jdk/java/util/Locale/LocaleProvidersCalendar.java new file mode 100644 index 0000000000000..93d11da772b8c --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersCalendar.java @@ -0,0 +1,74 @@ +/* + * 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 + * 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 8228465 8232871 8257964 + * @summary Test any Calendar Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersCalendar + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; + +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +public class LocaleProvidersCalendar { + + /* + * 8228465 (Windows only): Ensure correct ERA display name under HOST Windows + */ + @Test + @EnabledOnOs(WINDOWS) + public void gregCalEraHost() throws Throwable { + LocaleProviders.test("HOST", "bug8228465Test"); + } + + /* + * 8232871 (macOS only): Ensure correct Japanese calendar values under + * HOST Mac. + */ + @Test + @EnabledOnOs(MAC) + public void japaneseCalValuesHost() throws Throwable { + LocaleProviders.test("HOST", "bug8232871Test"); + } + + /* + * 8257964 (macOS/Windows only): Ensure correct Calendar::getMinimalDaysInFirstWeek + * value under HOST Windows / Mac. Only run against machine with underlying + * OS locale of en-GB. + */ + @Test + @EnabledOnOs({WINDOWS, MAC}) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + @EnabledIfSystemProperty(named = "user.country", matches = "GB") + public void minDaysFirstWeekHost() throws Throwable { + LocaleProviders.test("HOST", "bug8257964Test"); + } +} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java similarity index 59% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java rename to test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java index 9de8fa88ca708..e304dc73facf0 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java +++ b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, 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 @@ -19,22 +19,28 @@ * 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 8248695 + * @summary Test any java.time.DateTimeFormatter Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersDateTimeFormatter */ -public class TestGCLockerWithSerial { - public static void main(String[] args) { - String[] testArgs = {"2", "Tenured Gen"}; - TestGCLocker.main(testArgs); + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersDateTimeFormatter { + + /* + * 8248695: Ensure DateTimeFormatter::ofLocalizedDate does not throw exception + * under HOST (date only pattern leaks time field) + */ + @Test + public void dateOnlyJavaTimePattern() throws Throwable { + LocaleProviders.test("HOST", "bug8248695Test"); } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersFormat.java b/test/jdk/java/util/Locale/LocaleProvidersFormat.java new file mode 100644 index 0000000000000..0584b82b3184c --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersFormat.java @@ -0,0 +1,110 @@ +/* + * 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 + * 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 7198834 8001440 8013086 8013903 8027289 8232860 + * @summary Test any java.text.Format Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * providersrc.spi.src.tznp + * providersrc.spi.src.tznp8013086 + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersFormat + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledOnOs; + +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +public class LocaleProvidersFormat { + + /* + * 7198834: Ensure under Windows/HOST, adapter does not append an extra space for date patterns. + */ + @Test + @EnabledOnOs(WINDOWS) + public void dateFormatExtraSpace() throws Throwable { + LocaleProviders.test("HOST", "bug7198834Test"); + } + + /* + * 8001440: Ensure under CLDR, when number extension of the language + * tag is invalid, test program does not throw exception when calling + * NumberFormat::format. + */ + @Test + public void formatWithInvalidLocaleExtension() throws Throwable { + LocaleProviders.test("CLDR", "bug8001440Test"); + } + + /* + * 8013086: Ensure a custom TimeZoneNameProvider does not cause an NPE + * in simpleDateFormat, as SimpleDateFormat::matchZoneString expects the + * name array is fully filled with non-null names. + */ + @Test + public void simpleDateFormatWithTZNProvider() throws Throwable { + LocaleProviders.test("JRE,SPI", "bug8013086Test", "ja", "JP"); + LocaleProviders.test("COMPAT,SPI", "bug8013086Test", "ja", "JP"); + } + + /* + * 8013903 (Windows only): Ensure HOST adapter with Japanese locale produces + * the correct Japanese era, month, day names. + */ + @Test + @EnabledOnOs(WINDOWS) + public void windowsJapaneseDateFields() throws Throwable { + LocaleProviders.test("HOST,JRE", "bug8013903Test"); + LocaleProviders.test("HOST", "bug8013903Test"); + LocaleProviders.test("HOST,COMPAT", "bug8013903Test"); + } + + /* + * 8027289: Ensure if underlying system format locale is zh_CN, the Window's currency + * symbol under HOST provider is \u00A5, the yen (yuan) sign. + */ + @Test + @EnabledOnOs(WINDOWS) + @EnabledIfSystemProperty(named = "user.language", matches = "zh") + @EnabledIfSystemProperty(named = "user.country", matches = "CN") + public void windowsChineseCurrencySymbol() throws Throwable { + LocaleProviders.test("JRE,HOST", "bug8027289Test", "FFE5"); + LocaleProviders.test("COMPAT,HOST", "bug8027289Test", "FFE5"); + LocaleProviders.test("HOST", "bug8027289Test", "00A5"); + } + + /* + * 8232860 (macOS/Windows only): Ensure the Host adapter returns the number + * pattern for number/integer instances, which require optional fraction digits. + */ + @Test + @EnabledOnOs({WINDOWS, MAC}) + public void hostOptionalFracDigits() throws Throwable { + LocaleProviders.test("HOST", "bug8232860Test"); + } +} diff --git a/test/jdk/java/util/zip/ZipFile/CopyJar.java b/test/jdk/java/util/Locale/LocaleProvidersLogger.java similarity index 51% rename from test/jdk/java/util/zip/ZipFile/CopyJar.java rename to test/jdk/java/util/Locale/LocaleProvidersLogger.java index abeb1f3c46279..a6e15914c3b51 100644 --- a/test/jdk/java/util/zip/ZipFile/CopyJar.java +++ b/test/jdk/java/util/Locale/LocaleProvidersLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, 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 @@ -21,28 +21,29 @@ * questions. */ -/* @test 1.1 99/06/01 - @bug 4239446 - @summary Make sure the ZipEntry fields are correct. +/* + * @test + * @bug 8245241 8246721 8261919 + * @summary Test the Locale provider preference is logged + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm -Djdk.lang.Process.allowAmbiguousCommands=false LocaleProvidersLogger */ -import java.io.*; -import java.util.zip.*; +import org.junit.jupiter.api.Test; + +public class LocaleProvidersLogger { -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(); - } + /* + * 8245241 8246721 8261919: Ensure if an incorrect system property for locale providers is set, + * it should be logged and presented to the user. The option + * jdk.lang.Process.allowAmbiguousCommands=false is needed for properly escaping + * double quotes in the string argument. + */ + @Test + public void logIncorrectLocaleProvider() throws Throwable { + LocaleProviders.test("FOO", "bug8245241Test", + "Invalid locale provider adapter \"FOO\" ignored."); } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersRun.java b/test/jdk/java/util/Locale/LocaleProvidersRun.java index 947633a8e21ab..7b6e87247a005 100644 --- a/test/jdk/java/util/Locale/LocaleProvidersRun.java +++ b/test/jdk/java/util/Locale/LocaleProvidersRun.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 @@ -23,175 +23,151 @@ /* * @test - * @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577 - * 8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006 - * 8150432 8215913 8220227 8228465 8232871 8232860 8236495 8245241 - * 8246721 8248695 8257964 8261919 - * @summary tests for "java.locale.providers" system property - * @requires vm.flagless + * @bug 6336885 7196799 7197573 8008577 8010666 8013233 8015960 8028771 + * 8054482 8062006 8150432 8215913 8220227 8236495 + * @summary General Locale provider test (ex: adapter loading). See the + * other LocaleProviders* test classes for more specific tests (ex: + * java.text.Format related bugs). * @library /test/lib * @build LocaleProviders - * providersrc.spi.src.tznp - * providersrc.spi.src.tznp8013086 - * @modules java.base/sun.util.locale - * java.base/sun.util.locale.provider - * @run main/othervm -Djdk.lang.Process.allowAmbiguousCommands=false LocaleProvidersRun + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersRun */ import java.util.Locale; +import java.util.stream.Stream; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledOnOs; +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.condition.OS.WINDOWS; + +/* + * Note: If this test launches too many JVMs, consider increasing timeout. + * As the LocaleProvider is set during java startup time, this test and the subclasses + * will always have to launch a separate JVM for testing of different providers. + */ public class LocaleProvidersRun { - public static void main(String[] args) throws Throwable { - //get the platform default locales - Locale platDefLoc = Locale.getDefault(Locale.Category.DISPLAY); - String defLang = platDefLoc.getLanguage(); - String defCtry = platDefLoc.getCountry(); - System.out.println("DEFLANG = " + defLang); - System.out.println("DEFCTRY = " + defCtry); + private static String defLang; + private static String defCtry; + private static String defFmtLang; + private static String defFmtCtry; + + // Get the system default locale values. Used to decide param values for tests. + @BeforeAll + static void setUp() { + Locale platDefLoc = Locale.getDefault(Locale.Category.DISPLAY); Locale platDefFormat = Locale.getDefault(Locale.Category.FORMAT); - String defFmtLang = platDefFormat.getLanguage(); - String defFmtCtry = platDefFormat.getCountry(); - System.out.println("DEFFMTLANG = " + defFmtLang); - System.out.println("DEFFMTCTRY = " + defFmtCtry); - - //Run Test - //testing HOST is selected for the default locale, - // if specified on Windows or MacOSX + defLang = platDefLoc.getLanguage(); + defCtry = platDefLoc.getCountry(); + defFmtLang = platDefFormat.getLanguage(); + defFmtCtry = platDefFormat.getCountry(); + + // Print out system defaults for diagnostic purposes + System.out.printf("DEFLANG = %s, DEFCTRY = %s, DEFFMTLANG = %s, DEFFMTCTRY = %s", + defLang, defCtry, defFmtLang, defFmtCtry); + } + + /* + * Test the adapter loading logic in LocaleProviderAdapter. + * Ensures that correct fallbacks are implemented. + */ + @ParameterizedTest + @MethodSource + public void adapterTest(String prefList, String param1, + String param2, String param3) throws Throwable { + LocaleProviders.test(prefList, "adapterTest", param1, param2, param3); + } + + /* + * Data provider which only launches against the LocaleProvider::adapterTest + * method. The arguments are dictated based off the operating system/platform + * Locale. Tests against variety of provider orders. + */ + private static Stream adapterTest() { + // Testing HOST is selected for the default locale if specified on Windows or MacOSX String osName = System.getProperty("os.name"); String param1 = "JRE"; - if(osName.startsWith("Windows") || osName.startsWith("Mac")) { + if (osName.startsWith("Windows") || osName.startsWith("Mac")) { param1 = "HOST"; } - testRun("HOST,JRE", "adapterTest", param1, defLang, defCtry); - //testing HOST is NOT selected for the non-default locale, if specified - //Try to find the locale JRE supports which is not the platform default + // Testing HOST is NOT selected for the non-default locale, if specified + // try to find the locale JRE supports which is not the platform default // (HOST supports that one) String param2; String param3; - if (!defLang.equals("en") && !defFmtLang.equals("en")){ + if (!defLang.equals("en") && !defFmtLang.equals("en")) { param2 = "en"; param3 = "US"; - } else if(!defLang.equals("ja") && !defFmtLang.equals("ja")){ + } else if (!defLang.equals("ja") && !defFmtLang.equals("ja")) { param2 = "ja"; param3 = "JP"; } else { param2 = "zh"; param3 = "CN"; } - testRun("HOST,JRE", "adapterTest", "JRE", param2, param3); - - //testing SPI is NOT selected, as there is none. - testRun("SPI,JRE", "adapterTest", "JRE", "en", "US"); - testRun("SPI,COMPAT", "adapterTest", "JRE", "en", "US"); - - //testing the order, variant #1. This assumes en_GB DateFormat data are - // available both in JRE & CLDR - testRun("CLDR,JRE", "adapterTest", "CLDR", "en", "GB"); - testRun("CLDR,COMPAT", "adapterTest", "CLDR", "en", "GB"); - - //testing the order, variant #2. This assumes en_GB DateFormat data are - // available both in JRE & CLDR - testRun("JRE,CLDR", "adapterTest", "JRE", "en", "GB"); - testRun("COMPAT,CLDR", "adapterTest", "JRE", "en", "GB"); - - //testing the order, variant #3 for non-existent locale in JRE - // assuming "haw" is not in JRE. - testRun("JRE,CLDR", "adapterTest", "CLDR", "haw", ""); - testRun("COMPAT,CLDR", "adapterTest", "CLDR", "haw", ""); - - //testing the order, variant #4 for the bug 7196799. CLDR's "zh" data - // should be used in "zh_CN" - testRun("CLDR", "adapterTest", "CLDR", "zh", "CN"); - - //testing FALLBACK provider. SPI and invalid one cases. - testRun("SPI", "adapterTest", "FALLBACK", "en", "US"); - testRun("FOO", "adapterTest", "CLDR", "en", "US"); - testRun("BAR,SPI", "adapterTest", "FALLBACK", "en", "US"); - - //testing 7198834 fix. - testRun("HOST", "bug7198834Test", "", "", ""); - - //testing 8000245 fix. - testRun("JRE", "tzNameTest", "Europe/Moscow", "", ""); - testRun("COMPAT", "tzNameTest", "Europe/Moscow", "", ""); - - //testing 8000615 fix. - testRun("JRE", "tzNameTest", "America/Los_Angeles", "", ""); - testRun("COMPAT", "tzNameTest", "America/Los_Angeles", "", ""); - - //testing 8001440 fix. - testRun("CLDR", "bug8001440Test", "", "", ""); - - //testing 8010666 fix. - if (defLang.equals("en")) { - testRun("HOST", "bug8010666Test", "", "", ""); - } - - //testing 8013086 fix. - testRun("JRE,SPI", "bug8013086Test", "ja", "JP", ""); - testRun("COMPAT,SPI", "bug8013086Test", "ja", "JP", ""); - - //testing 8013903 fix. (Windows only) - testRun("HOST,JRE", "bug8013903Test", "", "", ""); - testRun("HOST", "bug8013903Test", "", "", ""); - testRun("HOST,COMPAT", "bug8013903Test", "", "", ""); - - //testing 8027289 fix, if the platform format default is zh_CN - // this assumes Windows' currency symbol for zh_CN is \u00A5, the yen - // (yuan) sign. - if (defFmtLang.equals("zh") && defFmtCtry.equals("CN")) { - testRun("JRE,HOST", "bug8027289Test", "FFE5", "", ""); - testRun("COMPAT,HOST", "bug8027289Test", "FFE5", "", ""); - testRun("HOST", "bug8027289Test", "00A5", "", ""); - } - //testing 8220227 fix. (Windows only) - if (!defLang.equals("en")) { - testRun("HOST", "bug8220227Test", "", "", ""); - } - - //testing 8228465 fix. (Windows only) - testRun("HOST", "bug8228465Test", "", "", ""); - - //testing 8232871 fix. (macOS only) - testRun("HOST", "bug8232871Test", "", "", ""); - - //testing 8232860 fix. (macOS/Windows only) - testRun("HOST", "bug8232860Test", "", "", ""); - - //testing 8245241 fix. - //jdk.lang.Process.allowAmbiguousCommands=false is needed for properly escaping - //double quotes in the string argument. - testRun("FOO", "bug8245241Test", - "Invalid locale provider adapter \"FOO\" ignored.", "", ""); - - //testing 8248695 fix. - testRun("HOST", "bug8248695Test", "", "", ""); + return Stream.of( + Arguments.of("HOST,JRE", param1, defLang, defCtry), + Arguments.of("HOST,JRE", "JRE", param2, param3), + + // Testing SPI is NOT selected, as there is none. + Arguments.of("SPI,JRE", "JRE", "en", "US"), + Arguments.of("SPI,COMPAT", "JRE", "en", "US"), + + // Testing the order, variant #1. This assumes en_GB DateFormat data are + // available both in JRE & CLDR + Arguments.of("CLDR,JRE", "CLDR", "en", "GB"), + Arguments.of("CLDR,COMPAT", "CLDR", "en", "GB"), + + // Testing the order, variant #2. This assumes en_GB DateFormat data are + // available both in JRE & CLDR + Arguments.of("JRE,CLDR", "JRE", "en", "GB"), + Arguments.of("COMPAT,CLDR", "JRE", "en", "GB"), + + // Testing the order, variant #3 for non-existent locale in JRE + // assuming "haw" is not in JRE. + Arguments.of("JRE,CLDR", "CLDR", "haw", ""), + Arguments.of("COMPAT,CLDR", "CLDR", "haw", ""), + + // Testing the order, variant #4 for the bug 7196799. CLDR's "zh" data + // should be used in "zh_CN" + Arguments.of("CLDR", "CLDR", "zh", "CN"), + + // Testing FALLBACK provider. SPI and invalid one cases. + Arguments.of("SPI", "FALLBACK", "en", "US"), + Arguments.of("FOO", "CLDR", "en", "US"), + Arguments.of("BAR,SPI", "FALLBACK", "en", "US") + ); + } - //testing 8257964 fix. (macOS/Windows only) - testRun("HOST", "bug8257964Test", "", "", ""); + /* + * 8010666: Test to ensure correct implementation of Currency/LocaleNameProvider + * in HOST Windows provider (English locale) + */ + @Test + @EnabledOnOs(WINDOWS) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void currencyNameProviderWindowsHost() throws Throwable { + LocaleProviders.test("HOST", "bug8010666Test"); } - private static void testRun(String prefList, String methodName, - String param1, String param2, String param3) throws Throwable { - - // Build process (without VM flags) - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-ea", "-esa", - "-cp", Utils.TEST_CLASS_PATH, - "-Djava.util.logging.config.class=LocaleProviders$LogConfig", - "-Djava.locale.providers=" + prefList, - "--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED", - "LocaleProviders", methodName, param1, param2, param3); - // Evaluate process status - int exitCode = ProcessTools.executeCommand(pb).getExitValue(); - if (exitCode != 0) { - throw new RuntimeException("Unexpected exit code: " + exitCode); - } + /* + * 8220227: Ensure Locale::getDisplayCountry does not display error message + * under HOST Windows (non-english locale) + */ + @Test + @EnabledOnOs(WINDOWS) + @DisabledIfSystemProperty(named = "user.language", matches = "en") + public void nonEnglishDisplayCountryHost() throws Throwable { + LocaleProviders.test("HOST", "bug8220227Test"); } } diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java similarity index 52% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java rename to test/jdk/java/util/Locale/LocaleProvidersTimeZone.java index a70a35daa63ea..46ab5054306df 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java +++ b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, 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 @@ -19,21 +19,33 @@ * 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 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 + * @test + * @bug 8000245 8000615 + * @summary Test any TimeZone Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * providersrc.spi.src.tznp + * providersrc.spi.src.tznp8013086 + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersTimeZone */ -public class TestGCLockerWithG1 { - public static void main(String[] args) { - String[] testArgs = {"2", "G1 Old Gen"}; - TestGCLocker.main(testArgs); + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersTimeZone { + + /* + * 8000245 and 8000615: Ensure preference is followed, even with a custom + * SPI defined. + */ + @Test + public void timeZoneWithCustomProvider() throws Throwable { + LocaleProviders.test("JRE", "tzNameTest", "Europe/Moscow"); + LocaleProviders.test("COMPAT", "tzNameTest", "Europe/Moscow"); + LocaleProviders.test("JRE", "tzNameTest", "America/Los_Angeles"); + LocaleProviders.test("COMPAT", "tzNameTest", "America/Los_Angeles"); } } diff --git a/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java b/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java new file mode 100644 index 0000000000000..ed9897f62911d --- /dev/null +++ b/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java @@ -0,0 +1,67 @@ +/* + * 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 8323659 + * @summary Ensures that the implementation of LTQ add and put methods does + * not call overridable offer. This test specifically asserts implementation + * details of LTQ. It's not that such impl details cannot change, just that + * such a change should be deliberately done with suitable consideration + * to compatibility. + * @run testng SubclassTest + */ + +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TimeUnit; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +@Test +public class SubclassTest { + + public void testPut() { + var queue = new TestLinkedTransferQueue(); + queue.put(new Object()); + assertEquals(queue.size(), 1); + } + + public void testAdd() { + var queue = new TestLinkedTransferQueue(); + queue.add(new Object()); + assertEquals(queue.size(), 1); + } + + public void testTimedOffer() { + var queue = new TestLinkedTransferQueue(); + queue.offer(new Object(), 60, TimeUnit.SECONDS); + assertEquals(queue.size(), 1); + } + + static class TestLinkedTransferQueue extends LinkedTransferQueue { + @Override + public boolean offer(Object obj) { + return false; // simulate fails to add the given obj + } + } +} diff --git a/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java b/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java index deb4b6b1616e5..3662fd74609eb 100644 --- a/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java +++ b/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java @@ -23,20 +23,45 @@ /* * @test + * @modules java.base/java.util.concurrent:open * @bug 4992438 6633113 * @summary Checks that fairness setting is respected. */ +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Fairness { - private static void testFairness(boolean fair, - final BlockingQueue q) + private final static VarHandle underlyingTransferQueueAccess; + + static { + try { + underlyingTransferQueueAccess = + MethodHandles.privateLookupIn( + SynchronousQueue.class, + MethodHandles.lookup() + ).findVarHandle( + SynchronousQueue.class, + "transferer", + Class.forName(SynchronousQueue.class.getName() + "$Transferer") + ); + } catch (Exception ex) { + throw new ExceptionInInitializerError(ex); + } + } + + + private static void testFairness(boolean fair, final SynchronousQueue q) throws Throwable { + final LinkedTransferQueue underlying = + (LinkedTransferQueue)underlyingTransferQueueAccess.get(q); + final ReentrantLock lock = new ReentrantLock(); final Condition ready = lock.newCondition(); final int threadCount = 10; @@ -53,9 +78,12 @@ private static void testFairness(boolean fair, } catch (Throwable t) { badness[0] = t; }}}; t.start(); ready.await(); - // Probably unnecessary, but should be bullet-proof - while (t.getState() == Thread.State.RUNNABLE) + // Wait until previous put:ing thread is provably parked + while (underlying.size() < (i + 1)) Thread.yield(); + + if (underlying.size() > (i + 1)) + throw new Error("Unexpected number of waiting producers: " + i); } for (int i = 0; i < threadCount; i++) { int j = q.take(); @@ -68,8 +96,8 @@ private static void testFairness(boolean fair, } public static void main(String[] args) throws Throwable { - testFairness(false, new SynchronousQueue()); - testFairness(false, new SynchronousQueue(false)); - testFairness(true, new SynchronousQueue(true)); + testFairness(false, new SynchronousQueue<>()); + testFairness(false, new SynchronousQueue<>(false)); + testFairness(true, new SynchronousQueue<>(true)); } } diff --git a/test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java b/test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java index f8bb222fb98ef..5a78d2791fe6d 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/zip/CopyZipFile.java b/test/jdk/java/util/zip/CopyZipFile.java index e6fa4bfe057c2..ae90e4b6400db 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/ZipFile/EnumAfterClose.java b/test/jdk/java/util/zip/ZipFile/EnumAfterClose.java deleted file mode 100644 index 38c00466e8f77..0000000000000 --- 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 0000000000000..e165e5d2a0a61 --- /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 e80fd7490762b..254f1d445eac7 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/GetDirEntry.java b/test/jdk/java/util/zip/ZipFile/GetDirEntry.java deleted file mode 100644 index e74fa6b315437..0000000000000 --- a/test/jdk/java/util/zip/ZipFile/GetDirEntry.java +++ /dev/null @@ -1,43 +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 - @bug 4206838 - @summary getEntry() will search for a directory - even without an ending '/'. - */ - -import java.io.*; -import java.util.zip.*; - -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"); - } - } - } -} 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 3488245175130..0000000000000 --- 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 33db2552986da..5aa9ee82f0f11 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 f20fc12ecc1fe..49f676ba555c0 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 38199e4694c3a..eaa3708578ea9 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/crash.jar b/test/jdk/java/util/zip/ZipFile/crash.jar deleted file mode 100644 index 8de20e7582e68..0000000000000 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 f5e6f57331703..0000000000000 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 2ca60bd4c0654..0000000000000 Binary files a/test/jdk/java/util/zip/ZipFile/input.zip and /dev/null differ diff --git a/test/jdk/javax/crypto/KEM/RSA_KEM.java b/test/jdk/javax/crypto/KEM/RSA_KEM.java index c46ded776236a..e666df432a68e 100644 --- a/test/jdk/javax/crypto/KEM/RSA_KEM.java +++ b/test/jdk/javax/crypto/KEM/RSA_KEM.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 @@ -28,6 +28,7 @@ * @modules java.base/sun.security.jca * java.base/sun.security.rsa * java.base/sun.security.util + * java.base/javax.crypto:+open */ import sun.security.jca.JCAUtil; import sun.security.rsa.RSACore; @@ -88,7 +89,7 @@ public static void main(String[] args) throws Exception { KeyPair kp = g.generateKeyPair(); for (RSAKEMParameterSpec kspec : kspecs) { SecretKey cek = KeyGenerator.getInstance("AES").generateKey(); - KEM kem1 = KEM.getInstance("RSA-KEM", p); + KEM kem1 = getKemImpl(p); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, cek, new IvParameterSpec(iv)); byte[] ciphertext = c.doFinal(msg); @@ -101,7 +102,7 @@ public static void main(String[] args) throws Exception { AlgorithmParameters a = AlgorithmParameters.getInstance("RSA-KEM", p); a.init(enc.params()); - KEM kem2 = KEM.getInstance("RSA-KEM", p); + KEM kem2 = getKemImpl(p); KEM.Decapsulator d = kem2.newDecapsulator(kp.getPrivate(), a.getParameterSpec(AlgorithmParameterSpec.class)); SecretKey k = d.decapsulate(enc.encapsulation(), 0, d.secretSize(), "AES"); Cipher c3 = Cipher.getInstance(kspec.encAlg); @@ -122,6 +123,14 @@ public static void main(String[] args) throws Exception { } } + // To bypass the JCE security provider signature check + private static KEM getKemImpl(Provider p) throws Exception { + var ctor = KEM.class.getDeclaredConstructor( + String.class, KEMSpi.class, Provider.class); + ctor.setAccessible(true); + return ctor.newInstance("RSA-KEM", new KEMImpl(), p); + } + static final String RSA_KEM = "1.2.840.113549.1.9.16.3.14"; static final String KEM_RSA = "1.0.18033.2.2.4"; diff --git a/test/jdk/javax/management/Introspector/ClassLeakTest.java b/test/jdk/javax/management/Introspector/ClassLeakTest.java index f6316f7e2c38c..3cef875f73c41 100644 --- a/test/jdk/javax/management/Introspector/ClassLeakTest.java +++ b/test/jdk/javax/management/Introspector/ClassLeakTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,9 +30,10 @@ * * @run clean ClassLeakTest * @run build ClassLeakTest - * @run main ClassLeakTest + * @run main/othervm ClassLeakTest */ +import java.lang.management.ManagementFactory; import java.lang.ref.WeakReference; import java.io.File; import java.nio.file.Paths; @@ -48,7 +49,6 @@ public static void main(String[] args) throws Exception { "Standard MBean does not retain a reference to " + "the MBean's class"); - String[] cpaths = System.getProperty("test.classes", ".") .split(File.pathSeparator); URL[] urls = new URL[cpaths.length]; @@ -56,25 +56,24 @@ public static void main(String[] args) throws Exception { urls[i] = Paths.get(cpaths[i]).toUri().toURL(); } - @SuppressWarnings("removal") - PrivateMLet mlet = new PrivateMLet(urls, null, false); - Class shadowClass = mlet.loadClass(TestMBean.class.getName()); + Test loaderMBean = new Test(urls); + Class shadowClass = loaderMBean.loadClass(TestMBean.class.getName()); if (shadowClass == TestMBean.class) { - System.out.println("TEST INVALID: MLet got original " + + System.out.println("TEST INVALID: MBean got original " + "TestMBean not shadow"); System.exit(1); } shadowClass = null; MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - ObjectName mletName = new ObjectName("x:type=mlet"); - mbs.registerMBean(mlet, mletName); + ObjectName loaderMBeanName = new ObjectName("x:name=loader"); + mbs.registerMBean(loaderMBean, loaderMBeanName); ObjectName testName = new ObjectName("x:type=test"); - mbs.createMBean(Test.class.getName(), testName, mletName); + mbs.createMBean(Test.class.getName(), testName, loaderMBeanName); ClassLoader testLoader = mbs.getClassLoaderFor(testName); - if (testLoader != mlet) { + if (testLoader != loaderMBean) { System.out.println("TEST INVALID: MBean's class loader is not " + "MLet: " + testLoader); System.exit(1); @@ -109,20 +108,19 @@ public static void main(String[] args) throws Exception { System.exit(1); } + WeakReference mbeanRef = new WeakReference(loaderMBean); mbs.unregisterMBean(testName); - mbs.unregisterMBean(mletName); - - WeakReference mletRef = new WeakReference(mlet); - mlet = null; + mbs.unregisterMBean(loaderMBeanName); + loaderMBean = null; System.out.println("MBean registered and unregistered, waiting for " + "garbage collector to collect class loader"); - for (int i = 0; i < 10000 && mletRef.get() != null; i++) { + for (int i = 0; i < 10000 && mbeanRef.get() != null; i++) { System.gc(); Thread.sleep(1); } - if (mletRef.get() == null) + if (mbeanRef.get() == null) System.out.println("Test passed: class loader was GC'd"); else { System.out.println("TEST FAILED: class loader was not GC'd"); @@ -136,10 +134,13 @@ public static interface TestMBean { public void setA(int a); } - public static class Test implements TestMBean { - public Test() {} - public Test(int x) {} - + public static class Test extends URLClassLoader implements TestMBean, PrivateClassLoader { + public Test() { + super(new URL[0], null); + } + public Test(URL[] urls) { + super(urls, null); + } public void bogus() {} public int getA() {return 0;} public void setA(int a) {} diff --git a/test/jdk/javax/management/MBeanServer/PostExceptionTest.java b/test/jdk/javax/management/MBeanServer/PostExceptionTest.java index a004acceee54b..3cd7a9bb4d0df 100644 --- a/test/jdk/javax/management/MBeanServer/PostExceptionTest.java +++ b/test/jdk/javax/management/MBeanServer/PostExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,8 @@ import javax.management.*; import java.io.Serializable; import java.net.URL; +import java.net.URLClassLoader; import java.util.EnumSet; -import javax.management.loading.MLet; public class PostExceptionTest { @@ -95,7 +95,7 @@ public static void main(String[] args) throws Exception { // We're going to test each cases, using each of the 4 createMBean // forms + registerMBean in turn to create the MBean. - // Wich method is used to create the MBean is indicated by "how" + // Which method is used to create the MBean is indicated by "how" // for (Case caze:cases) { for (CREATE how : CREATE.values()) { @@ -375,7 +375,7 @@ public ObjectInstance create(Throwable t, EnumSet where, MBeanServer server, ObjectName name) throws Exception { ExceptionallyHackyWombat.t = t; ExceptionallyHackyWombat.w = where; - final ObjectName loaderName = registerMLet(server); + final ObjectName loaderName = registerMB(server); return server.createMBean( ExceptionallyHackyWombat.class.getName(), name, loaderName); @@ -404,7 +404,7 @@ public ObjectInstance create(Throwable t, EnumSet where, }; return server.createMBean( ExceptionalWombat.class.getName(), name, - registerMLet(server), params, signature); + registerMB(server), params, signature); } }, REGISTER() { @@ -422,25 +422,23 @@ public ObjectInstance create(Throwable t, EnumSet where, public abstract ObjectInstance create(Throwable t, EnumSet where, MBeanServer server, ObjectName name) throws Exception; - // This is a bit of a hack - we use an MLet that delegates to the + // Create an MBean that delegates to the // System ClassLoader so that we can use createMBean form #2 and #3 // while still using the same class loader (system). // This is necessary to make the ExceptionallyHackyWombatMBean work ;-) // - public ObjectName registerMLet(MBeanServer server) throws Exception { - final ObjectName name = new ObjectName("test:type=MLet"); + public ObjectName registerMB(MBeanServer server) throws Exception { + final ObjectName name = new ObjectName("test:type=TestMBean"); if (server.isRegistered(name)) { return name; } - @SuppressWarnings("removal") - final MLet mlet = new MLet(new URL[0], - ClassLoader.getSystemClassLoader()); - return server.registerMBean(mlet, name).getObjectName(); + final TestMBean mbean = new Test(); + return server.registerMBean(mbean, name).getObjectName(); } } /** - *A Wombat MBean that can throw exceptions or errors in any of the + * A Wombat MBean that can throw exceptions or errors in any of the * MBeanRegistration methods. */ public static interface ExceptionalWombatMBean { @@ -514,4 +512,13 @@ public ExceptionallyHackyWombat() { } } + public static interface TestMBean { + } + + public static class Test extends URLClassLoader implements TestMBean { + public Test() { + super(new URL[0], ClassLoader.getSystemClassLoader()); + } + } + } diff --git a/test/jdk/javax/management/loading/ArrayClassTest.java b/test/jdk/javax/management/loading/ArrayClassTest.java index ce4cb4eff7aa8..fc911c8018df0 100644 --- a/test/jdk/javax/management/loading/ArrayClassTest.java +++ b/test/jdk/javax/management/loading/ArrayClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ public static void main(String[] args) throws Exception { urls[i] = Paths.get(cpaths[i]).toUri().toURL(); } - // Create an MLet that can load the same class names but + // Create a SpyLoader MBean that can load the same class names but // will produce different results. ClassLoader loader = new SpyLoader(urls); ObjectName loaderName = new ObjectName("test:type=SpyLoader"); @@ -105,10 +105,6 @@ public static class Z implements Serializable {} public static interface SpyLoaderMBean {} - /* We originally had this extend MLet but for some reason that - stopped the bug from happening. Some side-effect of registering - the MLet in the MBean server caused it not to fail when asked - to load Z[]. */ public static class SpyLoader extends URLClassLoader implements SpyLoaderMBean, PrivateClassLoader { public SpyLoader(URL[] urls) { @@ -117,19 +113,6 @@ public SpyLoader(URL[] urls) { super(urls, null); } - /* - public Class loadClass(String name) throws ClassNotFoundException { - System.out.println("loadClass: " + name); - return super.loadClass(name); - } - - public Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - System.out.println("loadClass: " + name + ", " + resolve); - return super.loadClass(name, resolve); - } - */ - public Class findClass(String name) throws ClassNotFoundException { System.out.println("findClass: " + name); if (false) diff --git a/test/jdk/javax/management/loading/DocumentRootTest.java b/test/jdk/javax/management/loading/DocumentRootTest.java deleted file mode 100644 index 73b1654d13517..0000000000000 --- a/test/jdk/javax/management/loading/DocumentRootTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 6500139 - * @summary Test parsing error when the mlet file is - * located in the web server's document root. - * @author Luis-Miguel Alventosa - * - * @run clean DocumentRootTest - * @run build DocumentRootTest - * @run main DocumentRootTest - */ - -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import javax.management.loading.MLetContent; - -@SuppressWarnings("removal") -public class DocumentRootTest { - public static int test(URL documentBase, URL codeBase) { - int error = 0; - MLetContent mc = new MLetContent( - documentBase, - new HashMap(), - new ArrayList(), - new ArrayList()); - System.out.println("\nACTUAL DOCUMENT BASE = " + mc.getDocumentBase()); - System.out.println("EXPECTED DOCUMENT BASE = " + documentBase); - if (!documentBase.equals(mc.getDocumentBase())) { - System.out.println("ERROR: Wrong document base"); - error++; - }; - System.out.println("ACTUAL CODEBASE = " + mc.getCodeBase()); - System.out.println("EXPECTED CODEBASE = " + codeBase); - if (!codeBase.equals(mc.getCodeBase())) { - System.out.println("ERROR: Wrong code base"); - error++; - }; - return error; - } - public static void main(String[] args) throws Exception { - int error = 0; - error += test(new URL("file:/mlet.txt"), new URL("file:/")); - error += test(new URL("http://localhost/mlet.txt"), new URL("http://localhost/")); - if (error > 0) { - System.out.println("\nTest FAILED!\n"); - throw new IllegalArgumentException("Test FAILED!"); - } else { - System.out.println("\nTest PASSED!\n"); - } - } -} diff --git a/test/jdk/javax/management/loading/GetMBeansFromURLTest.java b/test/jdk/javax/management/loading/GetMBeansFromURLTest.java deleted file mode 100644 index 31b86c72e8d22..0000000000000 --- a/test/jdk/javax/management/loading/GetMBeansFromURLTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 5018593 - * @summary Test that calling getMBeansFromURL(url) with a bogus URL on a - * given MLet instance throws a ServiceNotFoundException exception - * with a non null cause. - * @author Luis-Miguel Alventosa - * - * @run clean GetMBeansFromURLTest - * @run build GetMBeansFromURLTest - * @run main GetMBeansFromURLTest - */ - -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectName; -import javax.management.ServiceNotFoundException; -import javax.management.loading.MLet; - -@SuppressWarnings("removal") -public class GetMBeansFromURLTest { - - public static void main(String[] args) throws Exception { - - boolean error = false; - - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - - // Instantiate an MLet - // - System.out.println("Create the MLet"); - MLet mlet = new MLet(); - - // Register the MLet MBean with the MBeanServer - // - System.out.println("Register the MLet MBean"); - ObjectName mletObjectName = new ObjectName("Test:type=MLet"); - mbs.registerMBean(mlet, mletObjectName); - - // Call getMBeansFromURL - // - System.out.println("Call mlet.getMBeansFromURL()"); - try { - mlet.getMBeansFromURL("bogus://whatever"); - System.out.println("TEST FAILED: Expected " + - ServiceNotFoundException.class + - " exception not thrown."); - error = true; - } catch (ServiceNotFoundException e) { - if (e.getCause() == null) { - System.out.println("TEST FAILED: Got null cause in " + - ServiceNotFoundException.class + - " exception."); - error = true; - } else { - System.out.println("TEST PASSED: Got non-null cause in " + - ServiceNotFoundException.class + - " exception."); - error = false; - } - e.printStackTrace(System.out); - } - - // Unregister the MLet MBean - // - System.out.println("Unregister the MLet MBean"); - mbs.unregisterMBean(mletObjectName); - - // Release MBean server - // - System.out.println("Release the MBean server"); - MBeanServerFactory.releaseMBeanServer(mbs); - - // End Test - // - System.out.println("Bye! Bye!"); - if (error) System.exit(1); - } -} diff --git a/test/jdk/javax/management/loading/LibraryLoader/LibraryLoaderTest.java b/test/jdk/javax/management/loading/LibraryLoader/LibraryLoaderTest.java deleted file mode 100644 index 7760f85cfb6e2..0000000000000 --- a/test/jdk/javax/management/loading/LibraryLoader/LibraryLoaderTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4969756 - * @summary Test that the same native library coming from the same jar file can - * be loaded twice by two different MLets on the same JVM without conflict. - * @author Luis-Miguel Alventosa - * - * @run clean LibraryLoaderTest - * @run build LibraryLoaderTest - * @run main/othervm LibraryLoaderTest - */ - -import java.io.File; -import java.util.Set; -import javax.management.Attribute; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectInstance; -import javax.management.ObjectName; -import javax.management.ReflectionException; - -public class LibraryLoaderTest { - - private static final String mletInfo[][] = { - {"testDomain:type=MLet,index=0", "UseNativeLib0.html"}, - {"testDomain:type=MLet,index=1", "UseNativeLib1.html"} - }; - - public static void main(String args[]) throws Exception { - - String osName = System.getProperty("os.name"); - System.out.println("os.name=" + osName); - String osArch = System.getProperty("os.arch"); - System.out.println("os.name=" + osArch); - - // Check for supported platforms: - // - // Windows/x86 - // - if ((!(osName.startsWith("Windows") && osArch.equals("x86")))) { - System.out.println( - "This test runs only on Windows/x86 platforms"); - System.out.println("Bye! Bye!"); - return; - } - - String libPath = System.getProperty("java.library.path"); - System.out.println("java.library.path=" + libPath); - String testSrc = System.getProperty("test.src"); - System.out.println("test.src=" + testSrc); - String workingDir = System.getProperty("user.dir"); - System.out.println("user.dir=" + workingDir); - - String urlCodebase; - if (testSrc.startsWith("/")) { - urlCodebase = - "file:" + testSrc.replace(File.separatorChar, '/') + "/"; - } else { - urlCodebase = - "file:/" + testSrc.replace(File.separatorChar, '/') + "/"; - } - - // Create MBeanServer - // - MBeanServer server = MBeanServerFactory.newMBeanServer(); - - // Create MLet instances and call getRandom on the loaded MBeans - // - for (int i = 0; i < mletInfo.length; i++) { - // Create ObjectName for MLet - // - ObjectName mlet = new ObjectName(mletInfo[i][0]); - server.createMBean("javax.management.loading.MLet", mlet); - System.out.println("MLet = " + mlet); - - // Display old library directory and set it to test.classes - // - String libraryDirectory = - (String) server.getAttribute(mlet, "LibraryDirectory"); - System.out.println("Old Library Directory = " + - libraryDirectory); - Attribute attribute = - new Attribute("LibraryDirectory", workingDir); - server.setAttribute(mlet, attribute); - libraryDirectory = - (String) server.getAttribute(mlet, "LibraryDirectory"); - System.out.println("New Library Directory = " + - libraryDirectory); - - // Get MBeans from URL - // - String mletURL = urlCodebase + mletInfo[i][1]; - System.out.println("MLet URL = " + mletURL); - Object[] params = new Object[] { mletURL }; - String[] signature = new String[] {"java.lang.String"}; - Object res[] = ((Set) server.invoke(mlet, - "getMBeansFromURL", - params, - signature)).toArray(); - - // Iterate through all the loaded MBeans - // - for (int j = 0; j < res.length; j++) { - // Now ensure none of the returned objects is a Throwable - // - if (res[j] instanceof Throwable) { - ((Throwable) res[j]).printStackTrace(System.out); - throw new Exception("Failed to load the MBean #" + j - ,(Throwable)res[j]); - } - - // On each of the loaded MBeans, try to invoke their - // native operation - // - Object result = null; - try { - ObjectName mbean = - ((ObjectInstance) res[j]).getObjectName(); - result = server.getAttribute(mbean, "Random"); - System.out.println("MBean #" + j + " = " + mbean); - System.out.println("Random number = " + result); - } catch (ReflectionException e) { - e.getTargetException().printStackTrace(System.out); - throw new Exception ("A ReflectionException " - + "occured when attempting to invoke " - + "a native library based operation.", - e.getTargetException()); - } - } - } - } -} diff --git a/test/jdk/javax/management/loading/LibraryLoader/UseNativeLib0.html b/test/jdk/javax/management/loading/LibraryLoader/UseNativeLib0.html deleted file mode 100644 index 76323035bce08..0000000000000 --- a/test/jdk/javax/management/loading/LibraryLoader/UseNativeLib0.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -Test MLet. - - - diff --git a/test/jdk/javax/management/loading/LibraryLoader/UseNativeLib1.html b/test/jdk/javax/management/loading/LibraryLoader/UseNativeLib1.html deleted file mode 100644 index e089fbc967aa5..0000000000000 --- a/test/jdk/javax/management/loading/LibraryLoader/UseNativeLib1.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -Test MLet. - - - diff --git a/test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.c b/test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.c deleted file mode 100644 index 1cb7121545a2f..0000000000000 --- a/test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -JNIEXPORT jint JNICALL Java_UseNativeLib_getRandom(JNIEnv *env, jobject obj) { - return rand(); -} - -#ifdef __cplusplus -} -#endif diff --git a/test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.h b/test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.h deleted file mode 100644 index 33e2028040d30..0000000000000 --- a/test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.h +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#ifndef RandomGen -#define RandomGen -#ifdef __cplusplus -extern "C" { -#endif - -JNIEXPORT jint JNICALL Java_RandomGen_getRandom - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/test/jdk/javax/management/loading/LibraryLoader/native.jar b/test/jdk/javax/management/loading/LibraryLoader/native.jar deleted file mode 100644 index 7d8f1d3d06dc5..0000000000000 Binary files a/test/jdk/javax/management/loading/LibraryLoader/native.jar and /dev/null differ diff --git a/test/jdk/javax/management/loading/MLetCLR/MLetCommand.java b/test/jdk/javax/management/loading/MLetCLR/MLetCommand.java deleted file mode 100644 index 2973b15c2cbb1..0000000000000 --- a/test/jdk/javax/management/loading/MLetCLR/MLetCommand.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 4836468 - * @summary Test that the getClassLoaderRepository permission is not necessary - * for the test codebase as it is executed by the MLet code using - * doPrivileged. - * @author Luis-Miguel Alventosa - * - * @run clean MLetCommand - * @run build MLetCommand - * @run main/othervm/java.security.policy=policy MLetCommand - */ - -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectName; -import java.io.File; - -@SuppressWarnings("removal") -public class MLetCommand { - - public static void main(String[] args) throws Exception { - if (System.getSecurityManager() == null) - throw new IllegalStateException("No security manager installed!"); - - System.out.println("java.security.policy=" + - System.getProperty("java.security.policy")); - - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - // Register the MLetMBean - // - System.out.println("Create MLet MBean"); - ObjectName mlet = new ObjectName("MLetTest:name=MLetMBean"); - mbs.createMBean("javax.management.loading.MLet", mlet); - // Test OK! - // - System.out.println("Bye! Bye!"); - } -} diff --git a/test/jdk/javax/management/loading/MLetCLR/policy b/test/jdk/javax/management/loading/MLetCLR/policy deleted file mode 100644 index 4cabfd38c606d..0000000000000 --- a/test/jdk/javax/management/loading/MLetCLR/policy +++ /dev/null @@ -1,8 +0,0 @@ - -grant { - permission java.util.PropertyPermission "*", "read"; - permission javax.management.MBeanServerPermission "createMBeanServer"; - permission javax.management.MBeanPermission "javax.management.loading.MLet#-[-]", "instantiate"; - permission javax.management.MBeanPermission "javax.management.loading.MLet#-[MLetTest:name=MLetMBean]", "registerMBean"; - permission java.lang.RuntimePermission "createClassLoader"; -}; diff --git a/test/jdk/javax/management/loading/MLetContentTest.java b/test/jdk/javax/management/loading/MLetContentTest.java deleted file mode 100644 index 455a20533be29..0000000000000 --- a/test/jdk/javax/management/loading/MLetContentTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 4796780 - * @summary The class MLetContentTest becomes public - * @author Shanliang JIANG - * - * @run clean MLetContentTest - * @run build MLetContentTest - * @run main MLetContentTest - */ - -import java.util.*; -import java.net.*; - -import javax.management.loading.*; - -@SuppressWarnings("removal") -public class MLetContentTest { - public static void main(String[] args) throws Exception { - System.out.println(">>> General test for the public class MLetContent."); - - Map attributes = new HashMap(); - attributes.put("archive", archive); - attributes.put("Archive", "hahaha"); - - attributes.put("code", code); - attributes.put("codE", "hihi"); - - attributes.put("object", object); - attributes.put("obJect", "toto"); - - attributes.put("name", name); - attributes.put("NAME", "titi"); - - attributes.put("version", version); - attributes.put("VeRsIoN", "tttt"); - - List types = new ArrayList(); - types.add("my type"); - - List values = new ArrayList(); - values.add("my values"); - - URL url = new URL(baseUrl+myfile); - MLetContent content = new MLetContent(url, attributes, types, values); - - if (!attributes.equals(content.getAttributes())) { - throw new RuntimeException("The user specific attributes are changed."); - } - - if (!url.equals(content.getDocumentBase())) { - throw new RuntimeException("The user specific document bas is changed."); - } - - if (!archive.equals(content.getJarFiles())) { - throw new RuntimeException("The user specific archive files are changed."); - } - - if (!code.equals(content.getCode())) { - throw new RuntimeException("The user specific code is changed."); - } - - if (!object.equals(content.getSerializedObject())) { - throw new RuntimeException("The user specific object is changed."); - } - - if (!name.equals(content.getName())) { - throw new RuntimeException("The user specific name is changed."); - } - - if (!version.equals(content.getVersion())) { - throw new RuntimeException("The user specific version is changed."); - } - - if (!types.equals(content.getParameterTypes())) { - throw new RuntimeException("The user specific types are changed."); - } - - if (!values.equals(content.getParameterValues())) { - throw new RuntimeException("The user specific values are changed."); - } - - if (!baseUrl.equals(content.getCodeBase().toString())) { - throw new RuntimeException("The user specific base url are changed."); - } - - url = new URL(baseUrl); - attributes.put("codebase", codebase); - content = new MLetContent(url, attributes, types, values); - - if (!content.getCodeBase().toString().equals(baseUrl+codebase)) { - throw new RuntimeException("The user specific base url are changed."); - } - - final MyMLet myMlet = new MyMLet(); - - if (myMlet.check(null, null, null, content) != content.getCodeBase()) { - throw new RuntimeException("Failed to overrid the protected methed check"); - } - - System.out.println(">>> The test is well passed."); - } - - private static class MyMLet extends MLet { - public URL check(String version, - URL codebase, - String jarfile, - MLetContent content) { - return content.getCodeBase(); - } - } - - private static final String archive = "my jarfile"; - private static final String code = "my code"; - private static final String object = "my object"; - private static final String name = "my name"; - private static final String version = "my version"; - - private static final String myfile = "My file"; - private static final String baseUrl = "file:/tmp/test/"; - - private final static String codebase = "my code base/"; -} diff --git a/test/jdk/javax/management/loading/MLetInternalsTest.java b/test/jdk/javax/management/loading/MLetInternalsTest.java deleted file mode 100644 index 2007e68fddcf2..0000000000000 --- a/test/jdk/javax/management/loading/MLetInternalsTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import javax.management.loading.MLet; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeTest; - -import static org.testng.Assert.*; - -/* - * @test - * @bug 8058089 - * @summary Tests various internal functions provided by MLet for correctness - * @author Jaroslav Bachorik - * @modules java.management/javax.management.loading:open - * @run testng MLetInternalsTest - */ -@SuppressWarnings("removal") -public class MLetInternalsTest { - private final static String CONSTRUCT_PARAMETER = "constructParameter"; - - private final static Map testedMethods = new HashMap<>(); - - @BeforeClass - public static void setupClass() { - testedMethods.clear(); - try { - Method m = MLet.class.getDeclaredMethod( - CONSTRUCT_PARAMETER, - String.class, String.class - ); - m.setAccessible(true); - - testedMethods.put(CONSTRUCT_PARAMETER, m); - } catch (Exception ex) { - throw new Error(ex); - } - } - - private MLet mlet; - - @BeforeTest - public void setupTest() { - mlet = new MLet(); - } - - @Test - public void testConstructParameter() throws Exception { - assertEquals(constructParameter("120", "int"), 120); - assertEquals(constructParameter("120", "java.lang.Integer"), Integer.valueOf(120)); - assertEquals(constructParameter("120", "long"), 120L); - assertEquals(constructParameter("120", "java.lang.Long"), Long.valueOf(120)); - assertEquals(constructParameter("120.0", "float"), 120.0f); - assertEquals(constructParameter("120.0", "java.lang.Float"), Float.valueOf(120.0f)); - assertEquals(constructParameter("120.0", "double"), 120.0d); - assertEquals(constructParameter("120", "java.lang.Double"), Double.valueOf(120d)); - assertEquals(constructParameter("120", "java.lang.String"), "120"); - assertEquals(constructParameter("120", "byte"), (byte)120); - assertEquals(constructParameter("120", "java.lang.Byte"), (byte)120); - assertEquals(constructParameter("120", "short"), (short)120); - assertEquals(constructParameter("120", "java.lang.Short"), (short)120); - assertEquals(constructParameter("true", "boolean"), true); - assertEquals(constructParameter("true", "java.lang.Boolean"), Boolean.valueOf(true)); - } - - private Object constructParameter(String param, String type) throws Exception { - return testedMethods.get(CONSTRUCT_PARAMETER).invoke(mlet, param, type); - } -} diff --git a/test/jdk/javax/management/loading/MletParserLocaleTest.java b/test/jdk/javax/management/loading/MletParserLocaleTest.java deleted file mode 100644 index 4242caad0a2b8..0000000000000 --- a/test/jdk/javax/management/loading/MletParserLocaleTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 7065236 - * @summary Checking MletParser for Locale insensitive strings - * @author Harsha Wardhana B - * - * @run clean MletParserLocaleTest - * @run build MletParserLocaleTest - * @run main/othervm MletParserLocaleTest mlet4.html - */ - -import java.io.File; -import java.util.Locale; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectName; -import javax.management.loading.MLet; - -@SuppressWarnings("removal") -public class MletParserLocaleTest { - - public static void main(String[] args) throws Exception { - - boolean error = false; - - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - - // Get Default Locale - Locale loc = Locale.getDefault(); - - // Instantiate an MLet - // - System.out.println("Create the MLet"); - MLet mlet = new MLet(); - - // Register the MLet MBean with the MBeanServer - // - System.out.println("Register the MLet MBean"); - ObjectName mletObjectName = new ObjectName("Test:type=MLet"); - mbs.registerMBean(mlet, mletObjectName); - - // Call getMBeansFromURL - // - System.out.println("Call mlet.getMBeansFromURL()"); - String testSrc = System.getProperty("test.src"); - System.out.println("test.src = " + testSrc); - String urlCodebase; - if (testSrc.startsWith("/")) { - urlCodebase = - "file:" + testSrc.replace(File.separatorChar, '/') + "/"; - } else { - urlCodebase = - "file:/" + testSrc.replace(File.separatorChar, '/') + "/"; - } - String mletFile = urlCodebase + args[0]; - System.out.println("MLet File = " + mletFile); - try { - // Change default Locale to Turkish - Locale.setDefault(Locale.of("tr", "TR")); - mlet.getMBeansFromURL(mletFile); - System.out.println("Test Passes"); - } catch (Exception e) { - error = true; - e.printStackTrace(System.out); - }finally { - Locale.setDefault(loc); - } - - // Unregister the MLet MBean - // - System.out.println("Unregister the MLet MBean"); - mbs.unregisterMBean(mletObjectName); - - // Release MBean server - // - System.out.println("Release the MBean server"); - MBeanServerFactory.releaseMBeanServer(mbs); - - // End Test - // - System.out.println("Bye! Bye!"); - if (error) System.exit(1); - } -} diff --git a/test/jdk/javax/management/loading/ParserInfiniteLoopTest.java b/test/jdk/javax/management/loading/ParserInfiniteLoopTest.java deleted file mode 100644 index 4881d75556cb6..0000000000000 --- a/test/jdk/javax/management/loading/ParserInfiniteLoopTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 5042364 - * @summary Malformed MLet text file causes infinite loop in parser. - * The MLetParser goes into an infinite loop when a tag is not - * terminated with the corresponding '>' and an opening '<' for - * the subsequent tag is encountered. - * @author Luis-Miguel Alventosa - * - * @run clean ParserInfiniteLoopTest - * @run build ParserInfiniteLoopTest - * @run main/othervm ParserInfiniteLoopTest mlet1.html - * @run main/othervm ParserInfiniteLoopTest mlet2.html - * @run main/othervm ParserInfiniteLoopTest mlet3.html - */ - -import java.io.File; -import java.io.IOException; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectName; -import javax.management.ServiceNotFoundException; -import javax.management.loading.MLet; - -@SuppressWarnings("removal") -public class ParserInfiniteLoopTest { - - public static void main(String[] args) throws Exception { - - boolean error = false; - - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - - // Instantiate an MLet - // - System.out.println("Create the MLet"); - MLet mlet = new MLet(); - - // Register the MLet MBean with the MBeanServer - // - System.out.println("Register the MLet MBean"); - ObjectName mletObjectName = new ObjectName("Test:type=MLet"); - mbs.registerMBean(mlet, mletObjectName); - - // Call getMBeansFromURL - // - System.out.println("Call mlet.getMBeansFromURL()"); - String testSrc = System.getProperty("test.src"); - System.out.println("test.src = " + testSrc); - String urlCodebase; - if (testSrc.startsWith("/")) { - urlCodebase = - "file:" + testSrc.replace(File.separatorChar, '/') + "/"; - } else { - urlCodebase = - "file:/" + testSrc.replace(File.separatorChar, '/') + "/"; - } - String mletFile = urlCodebase + args[0]; - System.out.println("MLet File = " + mletFile); - try { - mlet.getMBeansFromURL(mletFile); - System.out.println( - "TEST FAILED: Expected ServiceNotFoundException not thrown"); - error = true; - } catch (ServiceNotFoundException e) { - if (e.getCause() == null) { - System.out.println("TEST FAILED: Got unexpected null cause " + - "in ServiceNotFoundException"); - error = true; - } else if (!(e.getCause() instanceof IOException)) { - System.out.println("TEST FAILED: Got unexpected non-null " + - "cause in ServiceNotFoundException"); - error = true; - } else { - System.out.println("TEST PASSED: Got expected non-null " + - "cause in ServiceNotFoundException"); - error = false; - } - e.printStackTrace(System.out); - } - - // Unregister the MLet MBean - // - System.out.println("Unregister the MLet MBean"); - mbs.unregisterMBean(mletObjectName); - - // Release MBean server - // - System.out.println("Release the MBean server"); - MBeanServerFactory.releaseMBeanServer(mbs); - - // End Test - // - System.out.println("Bye! Bye!"); - if (error) System.exit(1); - } -} diff --git a/test/jdk/javax/management/loading/mlet1.html b/test/jdk/javax/management/loading/mlet1.html deleted file mode 100644 index c2a33c0b522b5..0000000000000 --- a/test/jdk/javax/management/loading/mlet1.html +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/test/jdk/javax/management/loading/mlet2.html b/test/jdk/javax/management/loading/mlet2.html deleted file mode 100644 index 041a2af36f3dc..0000000000000 --- a/test/jdk/javax/management/loading/mlet2.html +++ /dev/null @@ -1,2 +0,0 @@ - - - diff --git a/test/jdk/javax/management/loading/mlet4.html b/test/jdk/javax/management/loading/mlet4.html deleted file mode 100644 index 522ab27252dc5..0000000000000 --- a/test/jdk/javax/management/loading/mlet4.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/jdk/javax/management/mxbean/MXBeanLoadingTest1.java b/test/jdk/javax/management/mxbean/MXBeanLoadingTest1.java index a677133ea50c1..244aad59bef38 100644 --- a/test/jdk/javax/management/mxbean/MXBeanLoadingTest1.java +++ b/test/jdk/javax/management/mxbean/MXBeanLoadingTest1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.lang.ref.WeakReference; import java.net.URL; +import java.net.URLClassLoader; import java.util.Arrays; import java.util.Map; import javax.management.Attribute; @@ -45,8 +46,9 @@ import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.MXBean; +import javax.management.ObjectInstance; import javax.management.ObjectName; -import javax.management.loading.PrivateMLet; +import javax.management.loading.PrivateClassLoader; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.CompositeType; @@ -60,7 +62,6 @@ public static void main(String[] args) throws Exception { test.run((Map)null); } - public void run(Map args) { System.out.println("MXBeanLoadingTest1::run: Start") ; @@ -81,38 +82,36 @@ public void run(Map args) { + ".class", ""); URL[] urls = new URL[]{new URL(clsLoadPath)}; - @SuppressWarnings("removal") - PrivateMLet mlet = new PrivateMLet(urls, null, false); - Class shadowClass = mlet.loadClass(TestMXBean.class.getName()); + Loader loader = new Loader(urls); + Class shadowClass = loader.loadClass(TestMXBean.class.getName()); if (shadowClass == TestMXBean.class) { - String message = "(ERROR) MLet got original TestMXBean, not shadow"; + String message = "(ERROR) Loader got original TestMXBean, not shadow"; System.out.println(message); throw new RuntimeException(message); } shadowClass = null; MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - ObjectName mletName = new ObjectName("x:type=mlet"); - mbs.registerMBean(mlet, mletName); + ObjectName loaderName = new ObjectName("x:type=myloader"); + mbs.registerMBean(loader, loaderName); ObjectName testName = new ObjectName("x:type=test"); - mbs.createMBean(Test.class.getName(), testName, mletName); + mbs.createMBean(Test.class.getName(), testName, loaderName); // That test fails because the MXBean instance is accessed via // a delegate OpenMBean which has ClassLoader testLoader = mbs.getClassLoaderFor(testName); - if (testLoader != mlet) { - System.out.println("MLet " + mlet); - String message = "(ERROR) MXBean's class loader is not MLet: " + if (testLoader != loader) { + System.out.println("Loader " + loader); + String message = "(ERROR) MXBean's class loader is not Loader: " + testLoader; System.out.println(message); throw new RuntimeException(message); } testLoader = null; - // Cycle get/set/get of the attribute of type Luis. // We check the set is effective. CompositeData cd_B = (CompositeData)mbs.getAttribute(testName, "B"); @@ -264,23 +263,20 @@ public void run(Map args) { throw new RuntimeException(message); } + WeakReference loaderRef = new WeakReference<>(loader); mbs.unregisterMBean(testName); - mbs.unregisterMBean(mletName); - - @SuppressWarnings("removal") - WeakReference mletRef = - new WeakReference(mlet); - mlet = null; + mbs.unregisterMBean(loaderName); + loader = null; System.out.println("MXBean registered and unregistered, waiting for " + "garbage collector to collect class loader"); - for (int i = 0; i < 10000 && mletRef.get() != null; i++) { + for (int i = 0; i < 10000 && loaderRef.get() != null; i++) { System.gc(); Thread.sleep(1); } - if (mletRef.get() == null) + if (loaderRef.get() == null) System.out.println("(OK) class loader was GC'd"); else { String message = "(ERROR) Class loader was not GC'd"; @@ -295,6 +291,14 @@ public void run(Map args) { System.out.println("MXBeanLoadingTest1::run: Done without any error") ; } + public static interface LoaderMBean { + } + + public static class Loader extends URLClassLoader implements LoaderMBean, PrivateClassLoader { + public Loader(URL[] urls) { + super(urls, null); + } + } // I agree the use of the MXBean annotation and the MXBean suffix for the // interface name are redundant but however harmless. diff --git a/test/jdk/javax/management/relation/NonArrayListTest.java b/test/jdk/javax/management/relation/NonArrayListTest.java index 0bb75f7ca8a0e..e2182fb0cceaf 100644 --- a/test/jdk/javax/management/relation/NonArrayListTest.java +++ b/test/jdk/javax/management/relation/NonArrayListTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,11 +35,10 @@ import java.util.*; import javax.management.*; import javax.management.relation.*; -import javax.management.loading.MLet; +import javax.management.timer.Timer; public class NonArrayListTest { - @SuppressWarnings("removal") // use of MLet public static void main(String[] args) throws Exception { MBeanServer mbs = MBeanServerFactory.createMBeanServer(); RelationService rs = new RelationService(true); @@ -51,18 +50,18 @@ public static void main(String[] args) throws Exception { RelationServiceMBean.class, false); - ObjectName mlet1Name = new ObjectName("r:type=MLet,instance=1"); - ObjectName mlet2Name = new ObjectName("r:type=MLet,instance=2"); - mbs.createMBean(MLet.class.getName(), mlet1Name); - mbs.createMBean(MLet.class.getName(), mlet2Name); + ObjectName mb1Name = new ObjectName("r:type=Timer,instance=1"); + ObjectName mb2Name = new ObjectName("r:type=Timer,instance=2"); + mbs.createMBean(Timer.class.getName(), mb1Name); + mbs.createMBean(Timer.class.getName(), mb2Name); - RoleInfo leftRoleInfo = new RoleInfo("left", MLet.class.getName()); - RoleInfo rightRoleInfo = new RoleInfo("right", MLet.class.getName()); + RoleInfo leftRoleInfo = new RoleInfo("left", Timer.class.getName()); + RoleInfo rightRoleInfo = new RoleInfo("right", Timer.class.getName()); ArrayList leftRoleValues = - new ArrayList(Arrays.asList(new ObjectName[] {mlet1Name})); + new ArrayList(Arrays.asList(new ObjectName[] {mb1Name})); ArrayList rightRoleValues = - new ArrayList(Arrays.asList(new ObjectName[] {mlet2Name})); + new ArrayList(Arrays.asList(new ObjectName[] {mb2Name})); Role leftRole = new Role("left", leftRoleValues); Role rightRole = new Role("right", rightRoleValues); diff --git a/test/jdk/javax/management/remote/mandatory/connection/IdleTimeoutTest.java b/test/jdk/javax/management/remote/mandatory/connection/IdleTimeoutTest.java index f0e6504c27a6d..2705f62a0bffa 100644 --- a/test/jdk/javax/management/remote/mandatory/connection/IdleTimeoutTest.java +++ b/test/jdk/javax/management/remote/mandatory/connection/IdleTimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, 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 @@ -211,9 +211,8 @@ private static boolean test(String proto,int opCount,int liCount) System.out.println("Operation[" + (i+1) +"]: starting at " + elapsed + "ms"); - final String name = "d:type=mlet,instance=" + i; - mbs.createMBean("javax.management.loading.MLet", - new ObjectName(name)); + final String name = "d:instance=" + i; + mbs.registerMBean(new Test(), new ObjectName(name)); if (i == (opCount-1)) startIdle = System.currentTimeMillis(); Thread.sleep(2); @@ -310,4 +309,17 @@ private static boolean test(String proto,int opCount,int liCount) System.out.println("*** ------------------------------------------"); return true; } + + public static interface TestMBean { + public int getA(); + public void setA(int a); + } + + public static class Test implements TestMBean { + public Test() {} + public Test(int x) {} + + public int getA() {return 0;} + public void setA(int a) {} + } } diff --git a/test/jdk/javax/management/remote/mandatory/loading/TargetMBeanTest.java b/test/jdk/javax/management/remote/mandatory/loading/TargetMBeanTest.java index 1908a31e2de72..9362fdc2453a9 100644 --- a/test/jdk/javax/management/remote/mandatory/loading/TargetMBeanTest.java +++ b/test/jdk/javax/management/remote/mandatory/loading/TargetMBeanTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,13 +49,13 @@ it will not find any such class loader (only the system class will use the wrong loader for deserialization and the attempt to invoke the target MBean with the deserialized object will fail. - We test this as follows. We fabricate an MLet that has the same set + We test this as follows. We create an MBean that has the same set of URLs as the 160 class loader, which we assume is the system class - loader (or at least, it is a URLClassLoader). This MLet is + loader (or at least, it is a URLClassLoader). This MBean is therefore a "shadow class loader" -- for every class name known to the 160 class loader, it can load the same name, but the result is not the same class, since it has not been loaded by the same loader. - Then, we use the MLet to create an RMIConnectorServer MBean. This + Then, we use the MBean to create an RMIConnectorServer MBean. This MBean is an instance of "shadow RMIConnectorServer", and its constructor has a parameter of type "shadow JMXServiceURL". If the constructor is invoked with "real JMXServiceURL" it will fail. @@ -72,10 +72,10 @@ it will not find any such class loader (only the system class import javax.management.remote.rmi.RMIConnectorServer; public class TargetMBeanTest { - private static final ObjectName mletName; + private static final ObjectName mbeanName; static { try { - mletName = new ObjectName("x:type=mlet"); + mbeanName = new ObjectName("x:type=TestMBean"); } catch (Exception e) { e.printStackTrace(); throw new Error(); @@ -101,17 +101,16 @@ public static void main(String[] args) throws Exception { URLClassLoader jrcl = (URLClassLoader) jmxRemoteClassLoader; URL[] urls = jrcl.getURLs(); - @SuppressWarnings("removal") - PrivateMLet mlet = new PrivateMLet(urls, null, false); - Class shadowClass = mlet.loadClass(JMXServiceURL.class.getName()); + TestMBean mbean = new Test(urls); + Class shadowClass = mbean.loadClass(JMXServiceURL.class.getName()); if (shadowClass == JMXServiceURL.class) { - System.out.println("TEST INVALID: MLet got original " + + System.out.println("TEST INVALID: Test MBean got original " + "JMXServiceURL not shadow"); System.exit(1); } MBeanServer mbs = MBeanServerFactory.newMBeanServer(); - mbs.registerMBean(mlet, mletName); + mbs.registerMBean(mbean, mbeanName); final String[] protos = {"rmi", "iiop", "jmxmp"}; boolean ok = true; @@ -155,7 +154,7 @@ private static boolean test(String proto, MBeanServer mbs) ObjectName on = new ObjectName("x:proto=" + proto + ",ok=yes"); mbsc.createMBean(RMIConnectorServer.class.getName(), on, - mletName, + mbeanName, new Object[] {rmiurl, null}, new String[] {JMXServiceURL.class.getName(), Map.class.getName()}); @@ -166,4 +165,18 @@ private static boolean test(String proto, MBeanServer mbs) cs.stop(); return true; } + + public static interface TestMBean { + public Class loadClass(String name) throws ClassNotFoundException; + } + + public static class Test extends URLClassLoader implements TestMBean { + public Test(URL[] urls) { + super(urls, null); + } + + public Class loadClass(String name) throws ClassNotFoundException { + return loadClass(name, false); + } + } } diff --git a/test/jdk/javax/management/remote/mandatory/notif/NotificationBufferTest.java b/test/jdk/javax/management/remote/mandatory/notif/NotificationBufferTest.java index 6d21127bf255e..4907dcd7dca04 100644 --- a/test/jdk/javax/management/remote/mandatory/notif/NotificationBufferTest.java +++ b/test/jdk/javax/management/remote/mandatory/notif/NotificationBufferTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ import javax.management.NotificationFilter; import javax.management.NotificationFilterSupport; import javax.management.ObjectName; -import javax.management.loading.MLet; +import javax.management.timer.Timer; import javax.management.remote.NotificationResult; import javax.management.remote.TargetedNotification; @@ -80,7 +80,6 @@ public static void main(String[] args) { } } - @SuppressWarnings("removal") // use of MLet private static boolean test() throws Exception { MBeanServer mbs = MBeanServerFactory.createMBeanServer(); @@ -121,7 +120,7 @@ private static boolean test() throws Exception { } System.out.println("Got earliest==next in initial fetch, OK"); - mbs.createMBean(MLet.class.getName(), null); + mbs.createMBean(Timer.class.getName(), new ObjectName(":type=Timer")); mbs.createMBean(NotificationSender.class.getName(), senderName); NotificationSenderMBean sender = (NotificationSenderMBean) diff --git a/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java b/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java index ba5b961180f60..03a69735ae43b 100644 --- a/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java +++ b/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,12 +91,6 @@ public static void main(String[] args) { // System.out.println("Create the MBean server"); MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - // Register the ClassPathClassLoaderMBean - // - System.out.println("Create ClassPathClassLoader MBean"); - ObjectName cpcl = - new ObjectName("ClassLoader:name=ClassPathClassLoader"); - mbs.createMBean("javax.management.loading.MLet", cpcl); // Register the SimpleStandardMBean // System.out.println("Create SimpleStandard MBean"); diff --git a/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java b/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java index f667b439b4ee2..45b10bfb3ec15 100644 --- a/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java +++ b/test/jdk/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,12 +89,6 @@ public static void main(String[] args) { // System.out.println("Create the MBean server"); MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - // Register the ClassPathClassLoaderMBean - // - System.out.println("Create ClassPathClassLoader MBean"); - ObjectName cpcl = - new ObjectName("ClassLoader:name=ClassPathClassLoader"); - mbs.createMBean("javax.management.loading.MLet", cpcl); // Register the SimpleStandardMBean // System.out.println("Create SimpleStandard MBean"); diff --git a/test/jdk/javax/swing/ImageIcon/LoadInterruptTest.java b/test/jdk/javax/swing/ImageIcon/LoadInterruptTest.java index b090662eba444..fd74378c584f4 100644 --- a/test/jdk/javax/swing/ImageIcon/LoadInterruptTest.java +++ b/test/jdk/javax/swing/ImageIcon/LoadInterruptTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ /* * @test - * @bug 8236987 + * @bug 8236987 8320328 * @summary Verifies ImageIcon constructor produces no output when the * thread is interrupted * @run main LoadInterruptTest @@ -74,6 +74,8 @@ private static void loadImageIcon() { Thread.currentThread().interrupt(); ImageIcon i = new ImageIcon("https://openjdk.org/images/openjdk.png"); int status = i.getImageLoadStatus(); + boolean interrupted = Thread.currentThread().isInterrupted(); + System.out.flush(); String outString = testOut.toString(StandardCharsets.UTF_8); @@ -84,6 +86,9 @@ private static void loadImageIcon() { if (status == MediaTracker.LOADING) { throw new RuntimeException("Test Case Failed!!! LOADING... status!!!"); } + + if (!interrupted) { + throw new RuntimeException("Interrupted state of the thread is not preserved"); + } } } - diff --git a/test/jdk/javax/swing/JTable/KeyBoardNavigation.java b/test/jdk/javax/swing/JTable/KeyBoardNavigation.java new file mode 100644 index 0000000000000..4a75b8c68d70f --- /dev/null +++ b/test/jdk/javax/swing/JTable/KeyBoardNavigation.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; + +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @key headful + * @bug 4112270 8264102 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Test Keyboard Navigation in JTable. + * @run main/manual KeyBoardNavigation + */ + +public class KeyBoardNavigation { + static JFrame frame; + public static PassFailJFrame passFailJFrame; + + static void initTest() throws Exception { + final String INSTRUCTIONS = """ + Instructions to Test: + 1. Refer the below keyboard navigation specs + (referenced from bug report 4112270). + 2. Check all combinations of navigational keys in all four modes + shift and control verifying each change to the selection against + the spec. If it does, press "pass", otherwise press "fail". + + Navigate In - Tab, shift-tab, control-tab, shift-control-tab + Return/shift-return - move focus one cell down/up. + Tab/shift-tab - move focus one cell right/left. + Up/down arrow - deselect current selection; move focus one cell up/down + Left/right arrow - deselect current selection; move focus one cell + left/right + PageUp/PageDown - deselect current selection; scroll up/down one + JViewport view; first visible cell in current + column gets focus + Control-PageUp/PageDown - deselect current selection; scroll + left/right one JViewport view; first + visible cell in current row gets + focus + Home/end - deselect current selection; move focus and view to + first/last cell in current row + Control-home/end - deselect current selection; move focus and view to + upper-left/lower-right cell in table + F2 - Allows editing in a cell containing information without + overwriting the information + Esc - Resets the cell content back to the state it was in before + editing started + Ctrl+A, Ctrl+/ = Select all + Ctrl+\\ = De-select all + Shift-up/down arrow - extend selection up/down one row + Shift-left/right arrow - extend selection left/right one column + Control-shift up/down arrow - extend selection to top/bottom of column + Shift-home/end - extend selection to left/right end of row + Control-shift-home/end - extend selection to beginning/end of data + Shift-PageUp/PageDown - extend selection up/down one view and scroll + table + Control-shift-PageUp/PageDown - extend selection left/right one view + and scroll table + """; + + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, Boolean.TRUE}, + {"Tom", "Ball", "Blue", 99, Boolean.FALSE}, + {"Alan", "Chung", "Green", 838, Boolean.FALSE}, + {"Jeff", "Dinkins", "Turquois", 8, Boolean.TRUE}, + {"Amy", "Fowler", "Yellow", 3, Boolean.FALSE}, + {"Brian", "Gerhold", "Green", 0, Boolean.FALSE}, + {"James", "Gosling", "Pink", 21, Boolean.FALSE}, + {"David", "Karlton", "Red", 1, Boolean.FALSE}, + {"Dave", "Kloba", "Yellow", 14, Boolean.FALSE}, + {"Peter", "Korn", "Purple", 12, Boolean.FALSE}, + {"Phil", "Milne", "Purple", 3, Boolean.FALSE}, + {"Dave", "Moore", "Green", 88, Boolean.FALSE}, + {"Hans", "Muller", "Maroon", 5, Boolean.FALSE}, + {"Rick", "Levenson", "Blue", 2, Boolean.FALSE}, + {"Tim", "Prinzing", "Blue", 22, Boolean.FALSE}, + {"Chester", "Rose", "Black", 0, Boolean.FALSE}, + {"Ray", "Ryan", "Gray", 77, Boolean.FALSE}, + {"Georges", "Saab", "Red", 4, Boolean.FALSE}, + {"Willie", "Walker", "Phthalo Blue", 4, Boolean.FALSE}, + {"Kathy", "Walrath", "Blue", 8, Boolean.FALSE}, + {"Arnaud", "Weber", "Green", 44, Boolean.FALSE} + }; + + frame = new JFrame("JTable Keyboard Navigation Test"); + passFailJFrame = new PassFailJFrame("Test Instructions", + INSTRUCTIONS, 5L, 15, 50); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, PassFailJFrame.Position.VERTICAL); + + JTable tableView = getTableDetails(names, data); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox<>(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + JScrollPane scrollPane = new JScrollPane(tableView); + scrollPane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollPane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollPane); + frame.pack(); + frame.setVisible(true); + } + + private static JTable getTableDetails(String[] names, Object[][] data) { + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set below. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + return tableView; + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + try { + initTest(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + passFailJFrame.awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.html b/test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.html deleted file mode 100644 index 324f84be764b9..0000000000000 --- a/test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Keyboard Navigation in JTable - - - -

    Keyboard Navigation in JTable

    - - - -

    - Refer to bug report 4112270 for spec of keyboard navigation. Check all combinations of navigational keys in all four modes shift and control verifying each change to the selection against the spec. - If it does, press "pass", otherwise press "fail". -


    -
    Philip Milne
    - - - - diff --git a/test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.java b/test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.java deleted file mode 100644 index 39ce0acdf3f32..0000000000000 --- a/test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.awt.Color; -import java.awt.Container; -import java.awt.Dimension; - -import javax.swing.DefaultCellEditor; -import javax.swing.JApplet; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.border.BevelBorder; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; -import javax.swing.table.TableModel; - - -/** - * @test - * @bug 4112270 - * @summary - * Keyboard Navigation in JTable - * @author milne - * @run applet/manual=yesno KeyBoardNavigation.html - */ -public class KeyBoardNavigation extends JApplet -{ - static void initTest(Container contentPane) - { - // Take the dummy data from SwingSet. - final String[] names = {"First Name", "Last Name", "Favorite Color", - "Favorite Number", "Vegetarian"}; - final Object[][] data = { - {"Mark", "Andrews", "Red", new Integer(2), new Boolean(true)}, - {"Tom", "Ball", "Blue", new Integer(99), new Boolean(false)}, - {"Alan", "Chung", "Green", new Integer(838), new Boolean(false)}, - {"Jeff", "Dinkins", "Turquois", new Integer(8), new Boolean(true)}, - {"Amy", "Fowler", "Yellow", new Integer(3), new Boolean(false)}, - {"Brian", "Gerhold", "Green", new Integer(0), new Boolean(false)}, - {"James", "Gosling", "Pink", new Integer(21), new Boolean(false)}, - {"David", "Karlton", "Red", new Integer(1), new Boolean(false)}, - {"Dave", "Kloba", "Yellow", new Integer(14), new Boolean(false)}, - {"Peter", "Korn", "Purple", new Integer(12), new Boolean(false)}, - {"Phil", "Milne", "Purple", new Integer(3), new Boolean(false)}, - {"Dave", "Moore", "Green", new Integer(88), new Boolean(false)}, - {"Hans", "Muller", "Maroon", new Integer(5), new Boolean(false)}, - {"Rick", "Levenson", "Blue", new Integer(2), new Boolean(false)}, - {"Tim", "Prinzing", "Blue", new Integer(22), new Boolean(false)}, - {"Chester", "Rose", "Black", new Integer(0), new Boolean(false)}, - {"Ray", "Ryan", "Gray", new Integer(77), new Boolean(false)}, - {"Georges", "Saab", "Red", new Integer(4), new Boolean(false)}, - {"Willie", "Walker", "Phthalo Blue", new Integer(4), new Boolean(false)}, - {"Kathy", "Walrath", "Blue", new Integer(8), new Boolean(false)}, - {"Arnaud", "Weber", "Green", new Integer(44), new Boolean(false)} - }; - - // Create a model of the data. - TableModel dataModel = new AbstractTableModel() { - // These methods always need to be implemented. - public int getColumnCount() { return names.length; } - public int getRowCount() { return data.length;} - public Object getValueAt(int row, int col) {return data[row][col];} - - // The default implementations of these methods in - // AbstractTableModel would work, but we can refine them. - public String getColumnName(int column) {return names[column];} - public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} - public boolean isCellEditable(int row, int col) {return true;} - public void setValueAt(Object aValue, int row, int column) { - System.out.println("Setting value to: " + aValue); - data[row][column] = aValue; - } - }; - - // Create the table - JTable tableView = new JTable(dataModel); - // Turn off auto-resizing so that we can set column sizes programmatically. - // In this mode, all columns will get their preferred widths, as set blow. - tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); - - // Create a combo box to show that you can use one in a table. - JComboBox comboBox = new JComboBox(); - comboBox.addItem("Red"); - comboBox.addItem("Orange"); - comboBox.addItem("Yellow"); - comboBox.addItem("Green"); - comboBox.addItem("Blue"); - comboBox.addItem("Indigo"); - comboBox.addItem("Violet"); - - TableColumn colorColumn = tableView.getColumn("Favorite Color"); - // Use the combo box as the editor in the "Favorite Color" column. - colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); - - // Set a pink background and tooltip for the Color column renderer. - DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); - colorColumnRenderer.setBackground(Color.pink); - colorColumnRenderer.setToolTipText("Click for combo box"); - colorColumn.setCellRenderer(colorColumnRenderer); - - // Set a tooltip for the header of the colors column. - TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); - if (headerRenderer instanceof DefaultTableCellRenderer) - ((DefaultTableCellRenderer)headerRenderer).setToolTipText("Hi Mom!"); - - // Set the width of the "Vegetarian" column. - TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); - vegetarianColumn.setPreferredWidth(100); - - // Show the values in the "Favorite Number" column in different colors. - TableColumn numbersColumn = tableView.getColumn("Favorite Number"); - DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { - public void setValue(Object value) { - int cellValue = (value instanceof Number) ? ((Number)value).intValue() : 0; - setForeground((cellValue > 30) ? Color.black : Color.red); - setText((value == null) ? "" : value.toString()); - } - }; - numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); - numbersColumn.setCellRenderer(numberColumnRenderer); - numbersColumn.setPreferredWidth(110); - - // Finish setting up the table. - JScrollPane scrollpane = new JScrollPane(tableView); - scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); - scrollpane.setPreferredSize(new Dimension(430, 200)); - - contentPane.add(scrollpane); - } - - - public void init() { - SwingUtilities.invokeLater(() -> { - try { - UIManager.setLookAndFeel( - "javax.swing.plaf.metal.MetalLookAndFeel"); - } catch (Exception e) { - throw new RuntimeException(e); - } - - initTest(getContentPane()); - }); - } -} diff --git a/test/jdk/javax/swing/JTree/8038113/bug8038113.html b/test/jdk/javax/swing/JTree/8038113/bug8038113.html deleted file mode 100644 index 1eb5480b517b2..0000000000000 --- a/test/jdk/javax/swing/JTree/8038113/bug8038113.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Verify that scaled icons are rendered smoothly. - -1. Run the test. -2. Check that Collapsed and Expanded JTree icons are drawn smoothly. -If so, press PASS, else press FAIL. - - - - - diff --git a/test/jdk/javax/swing/JTree/8038113/bug8038113.java b/test/jdk/javax/swing/JTree/8038113/bug8038113.java deleted file mode 100644 index fb094c4a25f7e..0000000000000 --- a/test/jdk/javax/swing/JTree/8038113/bug8038113.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -import java.awt.BasicStroke; -import java.awt.BorderLayout; -import java.awt.Graphics; -import java.awt.Graphics2D; -import javax.swing.Icon; -import javax.swing.JApplet; -import javax.swing.JPanel; -import javax.swing.JTree; -import javax.swing.SwingUtilities; -import javax.swing.plaf.basic.BasicTreeUI; - -/* @test - * @bug 8038113 - * @summary [macosx] JTree icon is not rendered in high resolution on Retina - * @run applet/manual=yesno bug8038113.html - */ -public class bug8038113 extends JApplet { - - @Override - public void init() { - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - - final JTree tree = new JTree(); - final BasicTreeUI treeUI = (BasicTreeUI) tree.getUI(); - - final JPanel panel = new JPanel() { - - @Override - public void paint(Graphics g) { - super.paint(g); - Graphics2D g2 = (Graphics2D) g; - g2.setStroke(new BasicStroke(0.5f)); - g2.scale(2, 2); - - int x = 10; - int y = 10; - Icon collapsedIcon = treeUI.getCollapsedIcon(); - Icon expandeIcon = treeUI.getExpandedIcon(); - int w = collapsedIcon.getIconWidth(); - int h = collapsedIcon.getIconHeight(); - collapsedIcon.paintIcon(this, g, x, y); - g.drawRect(x, y, w, h); - - y += 10 + h; - w = expandeIcon.getIconWidth(); - h = expandeIcon.getIconHeight(); - expandeIcon.paintIcon(this, g, x, y); - g.drawRect(x, y, w, h); - - } - }; - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(panel, BorderLayout.CENTER); - } - }); - } -} diff --git a/test/jdk/javax/swing/JTree/bug8038113.java b/test/jdk/javax/swing/JTree/bug8038113.java new file mode 100644 index 0000000000000..2b4c9ee461cd7 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug8038113.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/* @test + * @key headful + * @bug 8038113 8258979 + * @summary [macosx] JTree icon is not rendered in high resolution on Retina, + * collapsed icon is not rendered for GTK LAF as well. + * @run main bug8038113 + */ + +public class bug8038113 { + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + if (!laf.getName().contains("Motif")) { + System.out.println("Testing LAF: " + laf.getName()); + SwingUtilities.invokeAndWait(() -> test(laf)); + } + } + } + + public static void test(UIManager.LookAndFeelInfo laf) { + setLookAndFeel(laf); + final JTree tree = new JTree(); + final BasicTreeUI treeUI = (BasicTreeUI) tree.getUI(); + + Icon collapsedIcon = treeUI.getCollapsedIcon(); + Icon expandedIcon = treeUI.getExpandedIcon(); + BufferedImage img1 = paintToImage(expandedIcon); + BufferedImage img2 = paintToImage(collapsedIcon); + + if (!isImgRendered(img1)) { + try { + ImageIO.write(img1, "png", new File("Expanded_Icon_" + laf.getName() + ".png")); + } catch (IOException ignored) { + } + throw new RuntimeException("Test Failed, Expanded not rendered for: "+laf.getName()); + } + + if (!isImgRendered(img2)) { + try { + ImageIO.write(img2, "png", new File("Collapsed_Icon_" + laf.getName() + ".png")); + } catch (IOException ignored) { + } + throw new RuntimeException("Test Failed, Collapsed Icon not rendered for: "+laf.getName()); + } + System.out.println("Test Passed"); + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static BufferedImage paintToImage(Icon content) { + BufferedImage im = new BufferedImage(content.getIconWidth(), + content.getIconHeight(), TYPE_INT_RGB); + Graphics2D g = (Graphics2D) im.getGraphics(); + g.setBackground(Color.WHITE); + g.clearRect(0, 0, content.getIconWidth(), content.getIconHeight()); + content.paintIcon(new JLabel(), g, 0, 0); + g.dispose(); + return im; + } + + private static boolean isImgRendered(BufferedImage img) { + Color white = new Color(255, 255, 255); + for (int x = 0; x < img.getWidth(); ++x) { + for (int y = 0; y < img.getHeight(); ++y) { + if (img.getRGB(x, y) != white.getRGB()) { + return true; + } + } + } + return false; + } +} diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java index 7e0cc11173370..8977a574a627b 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java @@ -56,7 +56,7 @@ public static void main(String[] args) throws Exception { // Allocate many large objects quickly, to outrun the GC for (int i = 0; i < 100; i++) { - blackHole(new byte[16 * 1024 * 1024]); + blackHole(new byte[4 * 1024 * 1024]); } recording.stop(); diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdStartGeneratedFilename.java b/test/jdk/jdk/jfr/jcmd/TestJcmdStartGeneratedFilename.java new file mode 100644 index 0000000000000..d3e4dd7b2c2b6 --- /dev/null +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStartGeneratedFilename.java @@ -0,0 +1,70 @@ +/* + * 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 jdk.jfr.jcmd; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.CountDownLatch; + +import jdk.jfr.FlightRecorder; +import jdk.jfr.FlightRecorderListener; +import jdk.jfr.Recording; +import jdk.jfr.RecordingState; + +import jdk.test.lib.process.OutputAnalyzer; + +/** + * @test + * @summary Verify that a filename is generated + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.jcmd.TestJcmdStartGeneratedFilename + */ +public class TestJcmdStartGeneratedFilename { + + public static void main(String[] args) throws Exception { + CountDownLatch recordingClosed = new CountDownLatch(1); + FlightRecorder.addListener(new FlightRecorderListener() { + public void recordingStateChanged(Recording recording) { + if (recording.getState() == RecordingState.CLOSED) { + recordingClosed.countDown(); + } + } + }); + Path directory = Paths.get(".", "recordings"); + Files.createDirectories(directory); + JcmdHelper.jcmd("JFR.start", "duration=1s", "filename=" + directory); + recordingClosed.await(); + for (Path path : Files.list(directory).toList()) { + String file = path.toString(); + System.out.println("Found file: " + file); + if (file.endsWith(".jfr") && file.contains("hotspot-")) { + return; + } + } + throw new Exception("Expected dump file on the format hotspot-...jfr"); + } +} diff --git a/test/jdk/jdk/nio/zipfs/TestPosix.java b/test/jdk/jdk/nio/zipfs/TestPosix.java index f629dfef2225d..1fa3bdf2d7b26 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/jni/nullCaller/NullCallerTest.java b/test/jdk/jni/nullCaller/NullCallerTest.java index c7a25b693d048..106a90e89c85e 100644 --- a/test/jdk/jni/nullCaller/NullCallerTest.java +++ b/test/jdk/jni/nullCaller/NullCallerTest.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 @@ -37,17 +37,15 @@ // Test disabled on AIX since we cannot invoke the JVM on the primordial thread. -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import java.util.Properties; import jdk.test.lib.Platform; -import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.compiler.CompilerUtils; +import jdk.test.lib.process.ProcessTools; public class NullCallerTest { @@ -87,28 +85,10 @@ public static void main(String[] args) throws Exception { // build the module used for the test compileTestModule(); - var launcher = Path.of(System.getProperty("test.nativepath"), "NullCallerTest"); - var pb = new ProcessBuilder(launcher.toString()); - var env = pb.environment(); - - var libDir = Platform.libDir().toString(); - var vmDir = Platform.jvmLibDir().toString(); - - // set up shared library path - var sharedLibraryPathEnvName = Platform.sharedLibraryPathVariableName(); - env.compute(sharedLibraryPathEnvName, - (k, v) -> (v == null) ? libDir : v + File.pathSeparator + libDir); - env.compute(sharedLibraryPathEnvName, - (k, v) -> (v == null) ? vmDir : v + File.pathSeparator + vmDir); - - // launch the actual test - System.out.println("Launching: " + launcher + " shared library path: " + - env.get(sharedLibraryPathEnvName)); - new OutputAnalyzer(pb.start()) - .outputTo(System.out) - .errorTo(System.err) - .shouldHaveExitValue(0); - + ProcessBuilder pb = ProcessTools.createNativeTestProcessBuilder("NullCallerTest"); + System.out.println("Launching: " + pb.command() + " shared library path: " + + pb.environment().get(Platform.sharedLibraryPathVariableName())); + ProcessTools.executeProcess(pb).shouldHaveExitValue(0); } } diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java index 31db9d1a38083..22868ffaf3c11 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/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index ccdbd2d8e49cf..8ca47f718efa9 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -54,10 +54,14 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import jdk.test.lib.Platform; import jdk.test.lib.artifacts.Artifact; import jdk.test.lib.artifacts.ArtifactResolver; import jdk.test.lib.artifacts.ArtifactResolverException; @@ -743,10 +747,18 @@ private static String fetchNssLib(String osId) { return fetchNssLib(MACOSX_AARCH64.class); case "Linux-amd64-64": - return fetchNssLib(LINUX_X64.class); + if (Platform.isOracleLinux7()) { + throw new SkippedException("Skipping Oracle Linux prior to v8"); + } else { + return fetchNssLib(LINUX_X64.class); + } case "Linux-aarch64-64": - throw new SkippedException("Per JDK-8319128, skipping Linux aarch64 platforms."); + if (Platform.isOracleLinux7()) { + throw new SkippedException("Skipping Oracle Linux prior to v8"); + } else { + return fetchNssLib(LINUX_AARCH64.class); + } default: return null; } diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java index 5d6fb68aceba3..ddce6e8733dd6 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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,6 +21,7 @@ * questions. */ + import sun.security.pkcs11.SunPKCS11; import javax.security.auth.Subject; @@ -32,12 +33,10 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.security.*; -import java.util.Iterator; import java.util.PropertyPermission; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; import jdk.test.lib.util.ForceGC; +import jtreg.SkippedException; public class MultipleLogins { private static final String KS_TYPE = "PKCS11"; @@ -46,7 +45,13 @@ public class MultipleLogins { static final Policy DEFAULT_POLICY = Policy.getPolicy(); public static void main(String[] args) throws Exception { - String nssConfig = PKCS11Test.getNssConfig(); + String nssConfig = null; + try { + nssConfig = PKCS11Test.getNssConfig(); + } catch (SkippedException exc) { + System.out.println("Skipping test: " + exc.getMessage()); + } + if (nssConfig == null) { // No test framework support yet. Ignore System.out.println("No NSS config found. Skipping."); diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh index 5ad75ca1363a1..56a4fd6b80638 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh @@ -26,6 +26,7 @@ # @summary # @library /test/lib/ # @build jdk.test.lib.util.ForceGC +# jdk.test.lib.Platform # @run shell MultipleLogins.sh # set a few environment variables so that the shell-script can run stand-alone diff --git a/test/jdk/tools/jar/InputFilesTest.java b/test/jdk/tools/jar/InputFilesTest.java index 3dc08293a7677..6a0a7e2902188 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 0000000000000..ca7e2bc5f3009 --- /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 0000000000000..f8b230647fabe --- /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/javax/management/loading/LibraryLoader/jar_src/UseNativeLib.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java similarity index 74% rename from test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLib.java rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java index 11a5687ccfa66..99107602506c7 100644 --- a/test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLib.java +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 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,16 +21,7 @@ * questions. */ -public class UseNativeLib implements java.io.Serializable, UseNativeLibMBean { - - public native int getRandom(); - - static { - try { - System.loadLibrary("genrandom"); - } catch (Exception e) { - e.printStackTrace(); - } - } - +module com.foo { + requires jdk.httpserver; + requires net.foo; } diff --git a/test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLibMBean.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java similarity index 88% rename from test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLibMBean.java rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java index 8381146c4d784..360a989d9b339 100644 --- a/test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLibMBean.java +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 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,6 +21,6 @@ * questions. */ -public interface UseNativeLibMBean { - public int getRandom(); +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 0000000000000..c147923e75a0d --- /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/jdk/internal/shellsupport/doc/JavadocHelperTest.java b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java index 48106face35aa..d8539b8c656c7 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/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java b/test/langtools/jdk/javadoc/doclet/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java index 2931ae40f9d7e..3e5d978cc8f7d 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/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 56546955e0829..98a543e77a9bf 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 8322532 + * @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 @@ -627,4 +627,15 @@ public void underscoreAsLambdaParameter() { //JDK-8322532 " 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/sealed/SealedDiffConfigurationsTest.java b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java index 0b20fee0b81a3..16860d65cc232 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/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java index 355cd8ac20096..f8ce856bddd18 100644 --- a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java +++ b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java @@ -53,7 +53,7 @@ private static enum MethodGroup { IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isMusl", "isSlowDebugBuild", "hasSA", "isRoot", "isTieredSupported", "areCustomLoadersSupportedForCDS", "isDefaultCDSArchiveSupported", - "isHardenedOSX", "hasOSXPlistEntries"); + "isHardenedOSX", "hasOSXPlistEntries", "isOracleLinux7"); public final List methodNames; diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index 25cb8bc3d1e4f..92663c65d0fd5 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -33,6 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; import java.util.regex.Pattern; public class Platform { @@ -348,6 +349,20 @@ private static boolean isArch(String archnameRE) { .matches(); } + public static boolean isOracleLinux7() { + if (System.getProperty("os.name").toLowerCase().contains("linux") && + System.getProperty("os.version").toLowerCase().contains("el")) { + Pattern p = Pattern.compile("el(\\d+)"); + Matcher m = p.matcher(System.getProperty("os.version")); + if (m.find()) { + try { + return Integer.parseInt(m.group(1)) <= 7; + } catch (NumberFormatException nfe) {} + } + } + return false; + } + /** * Returns file extension of shared library, e.g. "so" on linux, "dll" on windows. * @return file extension diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java index ff7a8b66e160d..7f20d094b8e62 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadConstant.java @@ -41,7 +41,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CallOverheadConstant { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java index 21dd5eaac0516..d6b7028d287b9 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadVirtual.java @@ -41,7 +41,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CallOverheadVirtual { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java b/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java index a7cfe6169a8b3..de44b6957756e 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CriticalCalls.java @@ -51,7 +51,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CriticalCalls { static final MethodHandle PINNED; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java index cf1c9097454fd..740d8a2c78337 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverOfAddress.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(3) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) public class LoopOverOfAddress extends JavaLayouts { static final int ITERATIONS = 1_000_000; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java b/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java index 4114d258d08fc..47e6c0b1fd175 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/PointerInvoke.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointerInvoke extends CLayouts { Arena arena = Arena.ofConfined(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java b/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java index 5449d0d42d3b2..2050b3b2fb2e9 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/QSort.java @@ -46,7 +46,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class QSort extends CLayouts { static final Linker abi = Linker.nativeLinker(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java index d50b8d0900fa3..574268f1ffa26 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/StrLenTest.java @@ -48,7 +48,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class StrLenTest extends CLayouts { Arena arena = Arena.ofConfined(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java index 8ed0f10e0be5c..051ad94758e17 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/ToCStringTest.java @@ -51,7 +51,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class ToCStringTest extends CLayouts { @Param({"5", "20", "100", "200"}) diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java index 47b279679a3a0..f6f26f72a6a03 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/ToJavaStringTest.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED", "--enable-preview"}) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "--enable-preview", "-Djava.library.path=micro/native" }) public class ToJavaStringTest { private MemorySegment strSegment; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java b/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java index b627978c61583..4f1c0d5b528d2 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java @@ -45,7 +45,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class Upcalls extends CLayouts { static final Linker abi = Linker.nativeLinker(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java b/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java index d4be11e675c1d..9eabd7d0e7851 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/pointers/PointerBench.java @@ -46,7 +46,7 @@ @Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(3) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) @State(Scope.Benchmark) public class PointerBench { diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java index 34af75af0aba5..e649468fc9765 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAccess.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsAccess { BBPoint BBPoint; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java index 10e0be9535137..f9d254ed97521 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsAlloc.java @@ -41,7 +41,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsAlloc { @Benchmark diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java index aa6cc7bebe839..fa86137ff0211 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsDistance.java @@ -43,7 +43,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsDistance { BBPoint jniP1; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java index e17d2550aa788..51bd7738eda40 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/PointsFree.java @@ -42,7 +42,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class PointsFree { JNIPoint jniPoint; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java index 42fa54e8c7215..8ff8a4d1816fd 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/xor/XorTest.java @@ -19,7 +19,7 @@ @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class XorTest { diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerCompareTo.java b/test/micro/org/openjdk/bench/java/math/BigIntegerCompareTo.java new file mode 100644 index 0000000000000..e66ef1ec4d84e --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerCompareTo.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.math; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 5) +@Measurement(iterations = 3, time = 5) +@Fork(value = 3) +public class BigIntegerCompareTo { + + public enum Group {S, M, L} + + @Param({"S", "M", "L"}) + private Group group; + + private static final int MAX_LENGTH = Arrays.stream(Group.values()) + .mapToInt(p -> getNumbersOfBits(p).length) + .max() + .getAsInt(); + + private BigInteger[] numbers; + + @Setup + public void setup() { + int[] nBits = getNumbersOfBits(group); + numbers = new BigInteger[2 * MAX_LENGTH]; + for (int i = 0; i < MAX_LENGTH; i++) { + var p = Shared.createPair(nBits[i % nBits.length]); + numbers[2 * i] = p.x(); + numbers[2 * i + 1] = p.y(); + } + } + + private static int[] getNumbersOfBits(Group p) { + // the below arrays were derived from stats gathered from running tests in + // the security area, which is the biggest client of BigInteger in JDK + return switch (p) { + case S -> new int[]{0, 1, 2, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + case M -> new int[]{255, 256, 512}; + case L -> new int[]{1023, 1024, 1534, 1535, 1536}; + }; + } + + @Benchmark + public void testCompareTo(Blackhole bh) { + for (int i = 0; i < numbers.length; i += 2) + bh.consume(numbers[i].compareTo(numbers[i + 1])); + } +} diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerEquals.java b/test/micro/org/openjdk/bench/java/math/BigIntegerEquals.java new file mode 100644 index 0000000000000..5be2471ea049d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerEquals.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.math; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 5) +@Measurement(iterations = 3, time = 5) +@Fork(value = 3) +public class BigIntegerEquals { + + public enum Group {S, M, L} + + @Param({"S", "M", "L"}) + private Group group; + + private static final int MAX_LENGTH = Arrays.stream(Group.values()) + .mapToInt(p -> getNumbersOfBits(p).length) + .max() + .getAsInt(); + + private BigInteger[] numbers; + + @Setup + public void setup() { + int[] nBits = getNumbersOfBits(group); + numbers = new BigInteger[2 * MAX_LENGTH]; + for (int i = 0; i < MAX_LENGTH; i++) { + var p = Shared.createPair(nBits[i % nBits.length]); + numbers[2 * i] = p.x(); + numbers[2 * i + 1] = p.y(); + } + } + + private static int[] getNumbersOfBits(Group p) { + // the below arrays were derived from stats gathered from running tests in + // the security area, which is the biggest client of BigInteger in JDK + return switch (p) { + case S -> new int[]{1, 46}; + case M -> new int[]{129, 130, 251, 252, 253, 254, 255, 256}; + case L -> new int[]{382, 383, 384, 445, 446, 447, 448, 519, 520, 521}; + }; + } + + @Benchmark + public void testEquals(Blackhole bh) { + for (int i = 0; i < numbers.length; i += 2) + bh.consume(numbers[i].equals(numbers[i + 1])); + } +} diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerHashCode.java b/test/micro/org/openjdk/bench/java/math/BigIntegerHashCode.java new file mode 100644 index 0000000000000..92ed1b88c28ef --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerHashCode.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.math; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 5) +@Measurement(iterations = 3, time = 5) +@Fork(value = 3) +public class BigIntegerHashCode { + + public enum Group {S, M, L} + + @Param({"S", "M", "L"}) + private Group group; + + private static final int MAX_LENGTH = Arrays.stream(Group.values()) + .mapToInt(p -> getNumbersOfBits(p).length) + .max() + .getAsInt(); + + private BigInteger[] numbers; + + @Setup + public void setup() { + int[] nBits = getNumbersOfBits(group); + numbers = new BigInteger[MAX_LENGTH]; + for (int i = 0; i < MAX_LENGTH; i++) { + numbers[i] = Shared.createSingle(nBits[i % nBits.length]); + } + } + + private static int[] getNumbersOfBits(Group p) { + // the below arrays were derived from stats gathered from running tests in + // the security area, which is the biggest client of BigInteger in JDK + return switch (p) { + case S -> new int[]{2, 7, 13, 64}; + case M -> new int[]{256, 384, 511, 512, 521, 767, 768}; + case L -> new int[]{1024, 1025, 2047, 2048, 2049, 3072, 4096, 5120, 6144}; + }; + } + + @Benchmark + public void testHashCode(Blackhole bh) { + for (var n : numbers) + bh.consume(n.hashCode()); + } +} diff --git a/test/micro/org/openjdk/bench/java/math/Shared.java b/test/micro/org/openjdk/bench/java/math/Shared.java new file mode 100644 index 0000000000000..2f996d052c5ea --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/Shared.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.math; + +import java.math.BigInteger; +import java.util.Random; + +/////////////////////////////////////////////////////////////////////////////// +// THIS IS NOT A BENCHMARK +/////////////////////////////////////////////////////////////////////////////// +public final class Shared { + + // General note + // ============ + // + // Isn't there a simple way to get a BigInteger of the specified number + // of bits of magnitude? It does not seem like it. + // + // We cannot create a BigInteger of the specified number of bytes, + // directly and *cheaply*. This constructor does not do what you + // might think it does: + // + // BigInteger(int numBits, Random rnd) + // + // The only real direct option we have is this constructor: + // + // BigInteger(int bitLength, int certainty, Random rnd) + // + // But even with certainty == 0, it is not cheap. So, create the + // number with the closest number of bytes and then shift right + // the excess bits. + + private Shared() { + throw new AssertionError("This is a utility class"); + } + + // + // Creates a pair of same sign numbers x and y that minimally differ in + // magnitude. + // + // More formally: x.bitLength() == nBits and x.signum() == y.signum() + // and either + // + // * y.bitLength() == nBits, and + // * x.testBit(0) != y.testBit(0) + // + // or + // + // * y.bitLength() == nBits + 1 + // + // By construction, such numbers are unequal to each other, but the + // difference in magnitude is minimal. That way, the comparison + // methods, such as equals and compareTo, are forced to examine + // the _complete_ number representation. + // + // Assumptions on BigInteger mechanics + // =================================== + // + // 1. bigLength() is not consulted with for short-circuiting; if it is, + // then we have a problem with nBits={0,1} + // 2. new BigInteger(0, new byte[]{0}) and new BigInteger(1, new byte[]{1}) + // are not canonicalized to BigInteger.ZERO and BigInteger.ONE, + // respectively; if they are, then internal optimizations might be + // possible (BigInteger is not exactly a value-based class). + // 3. Comparison and equality are checked from the most significant bit + // to the least significant bit, not the other way around (for + // comparison it seems natural, but not for equality). If any + // of those are checked in the opposite direction, then the check + // might short-circuit. + // + public static Pair createPair(int nBits) { + if (nBits < 0) { + throw new IllegalArgumentException(String.valueOf(nBits)); + } else if (nBits == 0) { + var zero = new BigInteger(nBits, new byte[0]); + var one = new BigInteger(/* positive */ 1, new byte[]{1}); + return new Pair(zero, one); + } else if (nBits == 1) { + var one = new BigInteger(/* positive */ 1, new byte[]{1}); + var two = new BigInteger(/* positive */ 1, new byte[]{2}); + return new Pair(one, two); + } + int nBytes = (nBits + 7) / 8; + var r = new Random(); + var bytes = new byte[nBytes]; + r.nextBytes(bytes); + // Create a BigInteger of the exact bit length by: + // 1. ensuring that the most significant bit is set so that + // no leading zeros are truncated, and + // 2. explicitly specifying signum, so it's not calculated from + // the passed bytes, which must represent magnitude only + bytes[0] |= (byte) 0b1000_0000; + var x = new BigInteger(/* positive */ 1, bytes) + .shiftRight(nBytes * 8 - nBits); + var y = x.flipBit(0); + // do not rely on the assert statement in benchmark + if (x.bitLength() != nBits) + throw new AssertionError(x.bitLength() + ", " + nBits); + return new Pair(x, y); + } + + public record Pair(BigInteger x, BigInteger y) { + public Pair { + if (x.signum() == -y.signum()) // if the pair comprises positive and negative + throw new IllegalArgumentException("x.signum()=" + x.signum() + + ", y=signum()=" + y.signum()); + if (y.bitLength() - x.bitLength() > 1) + throw new IllegalArgumentException("x.bitLength()=" + x.bitLength() + + ", y.bitLength()=" + y.bitLength()); + } + } + + public static BigInteger createSingle(int nBits) { + if (nBits < 0) { + throw new IllegalArgumentException(String.valueOf(nBits)); + } + if (nBits == 0) { + return new BigInteger(nBits, new byte[0]); + } + int nBytes = (nBits + 7) / 8; + var r = new Random(); + var bytes = new byte[nBytes]; + r.nextBytes(bytes); + // Create a BigInteger of the exact bit length by: + // 1. ensuring that the most significant bit is set so that + // no leading zeros are truncated, and + // 2. explicitly specifying signum, so it's not calculated from + // the passed bytes, which must represent magnitude only + bytes[0] |= (byte) 0b1000_0000; + var x = new BigInteger(/* positive */ 1, bytes) + .shiftRight(nBytes * 8 - nBits); + if (x.bitLength() != nBits) + throw new AssertionError(x.bitLength() + ", " + nBits); + return x; + } +}