From d75d876eddfd2e59d9d28c2860fdab4ef3ec3c6b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 8 Jan 2024 07:30:21 +0000 Subject: [PATCH 001/153] 8322806: Eliminate -Wparentheses warnings in aarch64 code Reviewed-by: stefank, dholmes --- src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index f5b46a5351973..5c850c6bcbd65 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; } From 7edd10e5fa71dafbbad23455553b7f5ff0a75ac9 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 8 Jan 2024 08:20:07 +0000 Subject: [PATCH 002/153] 8321786: SegmentAllocator:allocateFrom(ValueLayout, MemorySegment,ValueLayout,long,long) spec mismatch in exception scenario Reviewed-by: mcimadamore --- .../java/lang/foreign/MemoryLayout.java | 2 +- .../java/lang/foreign/MemorySegment.java | 42 +++++++++- .../java/lang/foreign/SegmentAllocator.java | 6 +- .../foreign/AbstractMemorySegmentImpl.java | 8 +- .../classes/jdk/internal/foreign/Utils.java | 21 +++-- .../foreign/layout/AbstractLayout.java | 9 +-- .../foreign/layout/MemoryLayoutUtil.java | 7 -- test/jdk/java/foreign/TestLayouts.java | 4 +- .../foreign/TestMemoryAccessInstance.java | 7 ++ .../java/foreign/TestScopedOperations.java | 3 + .../java/foreign/TestSegmentAllocators.java | 77 +++++++++++++++++++ test/jdk/java/foreign/TestSegmentCopy.java | 60 +++++++++++++++ test/jdk/java/foreign/TestSegments.java | 11 ++- 13 files changed, 218 insertions(+), 39 deletions(-) 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/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/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/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)); From a40d397d5d785d29a2d5e848f872d11dab3bf80c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 8 Jan 2024 09:01:33 +0000 Subject: [PATCH 003/153] 8323110: Eliminate -Wparentheses warnings in ppc code Reviewed-by: dholmes --- src/hotspot/cpu/ppc/frame_ppc.inline.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index e7dca45b3c35a..861c6adc491e4 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)); } From eb9e754b3a439cc3ce36c2c9393bc8b250343844 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 8 Jan 2024 10:27:00 +0000 Subject: [PATCH 004/153] 8323065: Unneccesary CodeBlob lookup in CompiledIC::internal_set_ic_destination Reviewed-by: dlong, thartmann --- src/hotspot/share/code/compiledIC.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 09c6c4ff021b7dc719c0b1e0dfb041b03bba1b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Mon, 8 Jan 2024 11:41:51 +0000 Subject: [PATCH 005/153] 8322489: 22-b27: Up to 7% regression in all Footprint3-*-G1/ZGC Reviewed-by: egahlin --- src/hotspot/share/jfr/jfr.cpp | 4 +++- .../checkpoint/jfrCheckpointManager.cpp | 8 +++---- .../checkpoint/jfrCheckpointWriter.hpp | 1 + .../share/jfr/recorder/jfrRecorder.cpp | 24 +++++++++++++------ .../share/jfr/recorder/jfrRecorder.hpp | 1 + .../jfr/support/jfrDeprecationManager.cpp | 4 +++- 6 files changed, 29 insertions(+), 13 deletions(-) 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/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/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/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); From 71aac7a5fbb9a32181ada1a04b6a9622fe939c59 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 8 Jan 2024 11:45:18 +0000 Subject: [PATCH 006/153] 8276809: java/awt/font/JNICheck/FreeTypeScalerJNICheck.java shows JNI warning on Windows Reviewed-by: rschmelter, stuefe --- .../native/libawt/windows/awt_Win32GraphicsEnv.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp index 6c949b564e960..7dac7b17b1be4 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.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 @@ -126,9 +126,15 @@ BOOL DWMIsCompositionEnabled() { dwmIsCompositionEnabled = bRes; JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - JNU_CallStaticMethodByName(env, NULL, + jboolean hasException; + JNU_CallStaticMethodByName(env, &hasException, "sun/awt/Win32GraphicsEnvironment", "dwmCompositionChanged", "(Z)V", (jboolean)bRes); + if (hasException) { + J2dTraceLn(J2D_TRACE_INFO, "Exception occurred in DWMIsCompositionEnabled"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } return bRes; } From 458e563cd994f5e0f590c2144e8ed35d020d53d6 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 8 Jan 2024 12:57:55 +0000 Subject: [PATCH 007/153] 8310711: [IR Framework] Remove safepoint while printing handling Reviewed-by: thartmann, epeter --- .../parser/hotspot/CompilePhaseBlock.java | 31 +--- .../irmatching/parser/hotspot/State.java | 18 +- .../parser/hotspot/WriterThread.java | 51 ------ .../parser/hotspot/WriterThreads.java | 50 ------ .../tests/TestSafepointWhilePrinting.java | 152 ---------------- .../safepoint_while_printing_hotspot_pid.log | 163 ------------------ 6 files changed, 4 insertions(+), 461 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java delete mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThreads.java delete mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSafepointWhilePrinting.java delete mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/safepoint_while_printing_hotspot_pid.log 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/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java deleted file mode 100644 index 302bd203277e1..0000000000000 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/WriterThread.java +++ /dev/null @@ -1,51 +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.lib.ir_framework.driver.irmatching.parser.hotspot; - -/** - * This class represents a writer thread that emits log messages with LogCompilation. It saves and restores a currently - * parsed {@link LoggedMethod} if a {@link CompilePhaseBlock} was interrupted before reaching the block end tag. - * - * @see LoggedMethod - * @see CompilePhaseBlock - */ -class WriterThread { - private LoggedMethod loggedMethod = LoggedMethod.DONT_CARE; - - public static boolean isWriterThreadLine(String line) { - return line.startsWith(" 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)); - } -} 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 From fc047508170ab666857d740ccf541c2c3b612277 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 8 Jan 2024 13:30:23 +0000 Subject: [PATCH 008/153] 8321371: SpinPause() not implemented for bsd_aarch64/macOS Reviewed-by: eosterlund, dholmes, dcubed, eastigeevich, shade --- .../os_cpu/bsd_aarch64/os_bsd_aarch64.cpp | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) 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) { From 29397d29baac3b29083b1b5d6b2cb06e456af0c3 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 8 Jan 2024 13:32:17 +0000 Subject: [PATCH 009/153] 8320317: ObjectMonitor NotRunnable is not really an optimization Reviewed-by: eosterlund, dholmes, shade, dcubed --- src/hotspot/share/runtime/objectMonitor.cpp | 67 --------------------- src/hotspot/share/runtime/objectMonitor.hpp | 1 - 2 files changed, 68 deletions(-) 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); From c90768c93b26771bb8f4bdbe855d054ad089b337 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 8 Jan 2024 13:47:43 +0000 Subject: [PATCH 010/153] 8318444: Write details about compilation bailouts into crash reports Reviewed-by: thartmann, chagedorn --- src/hotspot/share/c1/c1_Compilation.cpp | 8 +- src/hotspot/share/c1/c1_Compilation.hpp | 3 + src/hotspot/share/ci/ciEnv.hpp | 4 +- .../share/compiler/compilationFailureInfo.cpp | 121 ++++++++++++++++++ .../share/compiler/compilationFailureInfo.hpp | 57 +++++++++ .../share/compiler/compiler_globals.hpp | 4 + src/hotspot/share/opto/compile.cpp | 12 ++ src/hotspot/share/opto/compile.hpp | 7 +- src/hotspot/share/runtime/os.cpp | 19 ++- src/hotspot/share/runtime/os.hpp | 1 + src/hotspot/share/utilities/vmError.cpp | 7 + 11 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 src/hotspot/share/compiler/compilationFailureInfo.cpp create mode 100644 src/hotspot/share/compiler/compilationFailureInfo.hpp diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index 53fb5fbcf9efe..4890cec5bfc7b 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" @@ -582,6 +584,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _has_monitors(false) , _install_code(install_code) , _bailout_msg(nullptr) +, _first_failure_details(nullptr) , _exception_info_list(nullptr) , _allocator(nullptr) , _code(buffer_blob) @@ -626,7 +629,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 +655,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/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/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/src/hotspot/share/compiler/compilationFailureInfo.hpp b/src/hotspot/share/compiler/compilationFailureInfo.hpp new file mode 100644 index 0000000000000..3de62eb69da5a --- /dev/null +++ b/src/hotspot/share/compiler/compilationFailureInfo.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP +#define SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP + +#if defined(COMPILER1) || defined(COMPILER2) + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/nativeCallStack.hpp" + +class outputStream; +class Symbol; + +class CompilationFailureInfo : public CHeapObj { + NativeCallStack _stack; + char* const _failure_reason; + const double _elapsed_seconds; + const int _compile_id; +public: + CompilationFailureInfo(const char* failure_reason); + ~CompilationFailureInfo(); + void print_on(outputStream* st) const; + + // Convenience function to print, safely, current compile failure iff + // current thread is compiler thread and there is an ongoing compilation + // and a pending failure. + // Otherwise prints nothing. + static bool print_pending_compilation_failure(outputStream* st); +}; + +#endif // defined(COMPILER1) || defined(COMPILER2) + +#endif // SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP diff --git a/src/hotspot/share/compiler/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/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 522654803aa19..30701c03707e9 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), @@ -926,6 +929,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), @@ -989,6 +993,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) { @@ -4358,6 +4367,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 01d0d727aa7b5..42f866df781c2 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -53,6 +53,7 @@ class Bundle; class CallGenerator; class CallStaticJavaNode; class CloneMap; +class CompilationFailureInfo; class ConnectionGraph; class IdealGraphPrinter; class InlineTree; @@ -363,6 +364,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. @@ -809,6 +811,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); @@ -1125,9 +1128,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/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..f5346c9230753 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); 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); From 57a65fe436a3617d64bbf0b02d4c7f7c2551448f Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Jan 2024 14:09:27 +0000 Subject: [PATCH 011/153] 8322003: JShell - Incorrect type inference in lists of records implementing interfaces Reviewed-by: vromero --- .../sun/tools/javac/parser/JavacParser.java | 24 ++-- .../share/classes/jdk/jshell/TaskFactory.java | 107 ++++++++++++++---- test/langtools/jdk/jshell/VariablesTest.java | 13 ++- 3 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index d83fb85b7f2c0..c962862e4bf7d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -967,6 +967,20 @@ public JCExpression parseType(boolean allowVar, List annotations) return result; } + protected JCExpression parseIntersectionType(int pos, JCExpression firstType) { + JCExpression t = firstType; + int pos1 = pos; + List targets = List.of(t); + while (token.kind == AMP) { + accept(AMP); + targets = targets.prepend(parseType()); + } + if (targets.length() > 1) { + t = toP(F.at(pos1).TypeIntersection(targets.reverse())); + } + return t; + } + public JCExpression unannotatedType(boolean allowVar) { return unannotatedType(allowVar, TYPE); } @@ -1337,15 +1351,7 @@ protected JCExpression term3() { case CAST: accept(LPAREN); selectTypeMode(); - int pos1 = pos; - List targets = List.of(t = parseType()); - while (token.kind == AMP) { - accept(AMP); - targets = targets.prepend(parseType()); - } - if (targets.length() > 1) { - t = toP(F.at(pos1).TypeIntersection(targets.reverse())); - } + t = parseIntersectionType(pos, parseType()); accept(RPAREN); selectExprMode(); JCExpression t1 = term3(); diff --git a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index ac777435102ba..5360e0d517fc7 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -80,8 +80,13 @@ import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.comp.Resolve; +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.parser.Lexer; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.parser.ScannerFactory; +import static com.sun.tools.javac.parser.Tokens.TokenKind.AMP; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -363,7 +368,7 @@ private ParseTask(SourceHandler sh, JavacTaskImpl task, DiagnosticCollector diagnostics, boolean forceExpression) { - super(sh, task, diagnostics); + super(sh, task, diagnostics, false); ReplParserFactory.preRegister(context, forceExpression); cuts = parse(); units = Util.stream(cuts) @@ -402,7 +407,7 @@ class AnalyzeTask extends BaseTask { private AnalyzeTask(SourceHandler sh, JavacTaskImpl task, DiagnosticCollector diagnostics) { - super(sh, task, diagnostics); + super(sh, task, diagnostics, true); cuts = analyze(); } @@ -440,7 +445,7 @@ class CompileTask extends BaseTask { CompileTask(SourceHandlersh, JavacTaskImpl jti, DiagnosticCollector diagnostics) { - super(sh, jti, diagnostics); + super(sh, jti, diagnostics, true); } boolean compile() { @@ -504,11 +509,15 @@ abstract class BaseTask { private BaseTask(SourceHandler sh, JavacTaskImpl task, - DiagnosticCollector diagnostics) { + DiagnosticCollector diagnostics, + boolean analyzeParserFactory) { this.sourceHandler = sh; this.task = task; context = task.getContext(); this.diagnostics = diagnostics; + if (analyzeParserFactory) { + JShellAnalyzeParserFactory.preRegister(context); + } } abstract Iterable cuTrees(); @@ -693,7 +702,7 @@ private void setVariableType(VarSnippet s) { Symtab syms = Symtab.instance(context); Names names = Names.instance(context); Log log = Log.instance(context); - ParserFactory parserFactory = ParserFactory.instance(context); + JShellAnalyzeParserFactory parserFactory = (JShellAnalyzeParserFactory) ParserFactory.instance(context); Attr attr = Attr.instance(context); Enter enter = Enter.instance(context); DisableAccessibilityResolve rs = (DisableAccessibilityResolve) Resolve.instance(context); @@ -709,26 +718,28 @@ private void setVariableType(VarSnippet s) { //ignore any errors: JavaFileObject prev = log.useSource(null); DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log); - try { - //parse the type as a cast, i.e. "() x". This is to support - //intersection types: - CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3); - Parser parser = parserFactory.newParser(buf, false, false, false); - JCExpression expr = parser.parseExpression(); - if (expr.hasTag(Tag.TYPECAST)) { - //if parsed OK, attribute and set the type: - var2OriginalType.put(field, field.type); - - JCTypeCast tree = (JCTypeCast) expr; - rs.runWithoutAccessChecks(() -> { - field.type = attr.attribType(tree.clazz, - enter.getEnvs().iterator().next().enclClass.sym); - }); + parserFactory.runPermitIntersectionTypes(() -> { + try { + //parse the type as a cast, i.e. "() x". This is to support + //intersection types: + CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3); + Parser parser = parserFactory.newParser(buf, false, false, false); + JCExpression expr = parser.parseExpression(); + if (expr.hasTag(Tag.TYPECAST)) { + //if parsed OK, attribute and set the type: + var2OriginalType.put(field, field.type); + + JCTypeCast tree = (JCTypeCast) expr; + rs.runWithoutAccessChecks(() -> { + field.type = attr.attribType(tree.clazz, + enter.getEnvs().iterator().next().enclClass.sym); + }); + } + } finally { + log.popDiagnosticHandler(h); + log.useSource(prev); } - } finally { - log.popDiagnosticHandler(h); - log.useSource(prev); - } + }); } } } @@ -777,4 +788,52 @@ public boolean isAccessible(Env env, Type site, Symbol sym, boolean private static final class Marker {} } + private static final class JShellAnalyzeParserFactory extends ParserFactory { + public static void preRegister(Context context) { + if (context.get(Marker.class) == null) { + context.put(parserFactoryKey, ((Factory) c -> new JShellAnalyzeParserFactory(c))); + context.put(Marker.class, new Marker()); + } + } + + private final ScannerFactory scannerFactory; + private boolean permitIntersectionTypes; + + public JShellAnalyzeParserFactory(Context context) { + super(context); + this.scannerFactory = ScannerFactory.instance(context); + } + + /**Run the given Runnable with intersection type permitted. + * + * @param r Runnnable to run + */ + public void runPermitIntersectionTypes(Runnable r) { + boolean prevPermitIntersectionTypes = permitIntersectionTypes; + try { + permitIntersectionTypes = true; + r.run(); + } finally { + permitIntersectionTypes = prevPermitIntersectionTypes; + } + } + + @Override + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { + com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); + return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, parseModuleInfo) { + @Override + public JCExpression parseType(boolean allowVar, com.sun.tools.javac.util.List annotations) { + int pos = token.pos; + JCExpression t = super.parseType(allowVar, annotations); + if (permitIntersectionTypes) { + t = parseIntersectionType(pos, t); + } + return t; + } + }; + } + + private static final class Marker {} + } } 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);"); + } + } From c8fa3e21e6a4fd7846932b545a1748cc1dc6d9f1 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 8 Jan 2024 14:55:17 +0000 Subject: [PATCH 012/153] 8320310: CompiledMethod::has_monitors flag can be incorrect Reviewed-by: vlivanov, thartmann --- src/hotspot/share/c1/c1_Compilation.cpp | 6 +--- src/hotspot/share/c1/c1_GraphBuilder.cpp | 22 ++++++------ src/hotspot/share/opto/locknode.cpp | 6 ---- src/hotspot/share/opto/parse1.cpp | 2 +- .../share/runtime/continuationFreezeThaw.cpp | 34 +++++++++---------- 5 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index 4890cec5bfc7b..bef1fae7f7496 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -390,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(); @@ -581,7 +577,7 @@ 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) diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index fb2aa28ec86a3..fe9a8a478365d 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -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/opto/locknode.cpp b/src/hotspot/share/opto/locknode.cpp index 640109e6c42a4..6354df1ec5914 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 @@ -198,10 +196,6 @@ void Parse::do_monitor_enter() { void Parse::do_monitor_exit() { kill_dead_locals(); - // need to set it for monitor exit as well. - // OSR compiled methods can start with lock taken - C->set_has_monitors(true); - pop(); // Pop oop to unlock // Because monitors are guaranteed paired (else we bail out), we know // the matching Lock for this Unlock. Hence we know there is no need diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index d784f3f3240a3..96db18f774fe7 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -423,7 +423,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) C->set_has_reserved_stack_access(true); } - if (parse_method->is_synchronized()) { + if (parse_method->is_synchronized() || parse_method->has_monitor_bytecodes()) { C->set_has_monitors(true); } 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"); From 2acb5bd9924511b58b0e57ea9eb6c2dee9fd3ee8 Mon Sep 17 00:00:00 2001 From: Ilya Gavrilin Date: Mon, 8 Jan 2024 15:53:58 +0000 Subject: [PATCH 013/153] 8322790: RISC-V: Tune costs for shuffles with no conversion Reviewed-by: rehn, fyang --- src/hotspot/cpu/riscv/riscv.ad | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index d5a95b2e3ba5b..7e1291f49d74c 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 @@ -8674,7 +8675,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, fRegF src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.x.w $dst, $src\t#@MoveF2I_reg_reg" %} @@ -8692,7 +8693,7 @@ instruct MoveI2F_reg_reg(fRegF dst, iRegI src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.w.x $dst, $src\t#@MoveI2F_reg_reg" %} @@ -8710,7 +8711,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, fRegD src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.x.d $dst, $src\t#@MoveD2L_reg_reg" %} @@ -8728,7 +8729,7 @@ instruct MoveL2D_reg_reg(fRegD dst, iRegL src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.d.x $dst, $src\t#@MoveL2D_reg_reg" %} From 827c71dac9a5732f70bc7341743bce314cad302f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 8 Jan 2024 16:10:21 +0000 Subject: [PATCH 014/153] 8310190: C2 SuperWord: AlignVector is broken, generates misaligned packs Co-authored-by: Christian Hagedorn Reviewed-by: kvn, chagedorn --- src/hotspot/cpu/aarch64/aarch64.ad | 20 +- src/hotspot/cpu/x86/x86.ad | 15 + src/hotspot/share/adlc/formssel.cpp | 3 +- src/hotspot/share/opto/c2_globals.hpp | 6 +- src/hotspot/share/opto/c2compiler.cpp | 10 +- src/hotspot/share/opto/chaitin.cpp | 16 +- src/hotspot/share/opto/classes.hpp | 3 +- src/hotspot/share/opto/compile.cpp | 27 +- src/hotspot/share/opto/machnode.cpp | 9 +- src/hotspot/share/opto/node.hpp | 1 + src/hotspot/share/opto/superword.cpp | 859 ++-- src/hotspot/share/opto/superword.hpp | 39 +- src/hotspot/share/opto/vectorization.cpp | 675 ++- src/hotspot/share/opto/vectorization.hpp | 451 +- src/hotspot/share/opto/vectornode.hpp | 43 +- .../TestVectorizationMismatchedAccess.java | 17 +- .../lib/ir_framework/TestFramework.java | 3 +- .../loopopts/superword/TestAlignVector.java | 1479 ++++++ .../superword/TestAlignVectorFuzzer.java | 1353 +++++ .../superword/TestDependencyOffsets.java | 4489 ++++++++++++++--- .../superword/TestMovingLoadBeforeStore.java | 3 +- .../loopopts/superword/TestMulAddS2I.java | 18 +- .../TestBufferVectorization.java | 314 +- 23 files changed, 8530 insertions(+), 1323 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java 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/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/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/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index dc629de1bdfdb..885c0dd75a784 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/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 30701c03707e9..acce455b7265d 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1065,7 +1065,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 && @@ -3707,6 +3707,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: 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/node.hpp b/src/hotspot/share/opto/node.hpp index 7e9c5196942fb..015bf5d5c72ca 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; diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index c3f0a60af20ff..4b1d9e5457291 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)); @@ -3553,167 +3466,337 @@ LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { return dep; } +#define TRACE_ALIGN_VECTOR_NODE(node) { \ + DEBUG_ONLY( \ + if (is_trace_align_vector()) { \ + tty->print(" " #node ": "); \ + node->dump(); \ + } \ + ) \ +} \ + +// Ensure that the main loop vectors are aligned by adjusting the pre loop limit. We memory-align +// the address of "align_to_ref" to the maximal possible vector width. We adjust the pre-loop +// iteration count by adjusting the pre-loop limit. +void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { + const MemNode* align_to_ref = _align_to_ref; + assert(align_to_ref != nullptr, "align_to_ref must be set"); + assert(lp()->is_main_loop(), "can only do alignment for main loop"); -//----------------------------align_initial_loop_index--------------------------- -// Adjust pre-loop limit so that in main loop, a load/store reference -// to align_to_ref will be a position zero in the vector. -// (iv + k) mod vector_align == 0 -void SuperWord::align_initial_loop_index(MemNode* align_to_ref) { - assert(lp()->is_main_loop(), ""); - CountedLoopEndNode* pre_end = lp()->pre_loop_end(); - Node* pre_opaq1 = pre_end->limit(); - assert(pre_opaq1->Opcode() == Op_Opaque1, ""); - Opaque1Node* pre_opaq = (Opaque1Node*)pre_opaq1; - Node* lim0 = pre_opaq->in(1); + // The opaque node for the limit, where we adjust the input + Opaque1Node* pre_opaq = lp()->pre_loop_end()->limit()->as_Opaque1(); - // Where we put new limit calculations + // Current pre-loop limit. + Node* old_limit = pre_opaq->in(1); + + // Where we put new limit calculations. Node* pre_ctrl = lp()->pre_loop_head()->in(LoopNode::EntryControl); - // Ensure the original loop limit is available from the - // pre-loop Opaque1 node. + // Ensure the original loop limit is available from the pre-loop Opaque1 node. Node* orig_limit = pre_opaq->original_loop_limit(); assert(orig_limit != nullptr && _igvn.type(orig_limit) != Type::TOP, ""); VPointer align_to_ref_p(align_to_ref, phase(), lpt(), nullptr, false); assert(align_to_ref_p.valid(), "sanity"); - // Given: - // lim0 == original pre loop limit - // V == v_align (power of 2) - // invar == extra invariant piece of the address expression - // e == offset [ +/- invar ] + // For the main-loop, we want the address of align_to_ref to be memory aligned + // with some alignment width (aw, a power of 2). When we enter the main-loop, + // we know that iv is equal to the pre-loop limit. If we adjust the pre-loop + // limit by executing adjust_pre_iter many extra iterations, we can change the + // alignment of the address. // - // When reassociating expressions involving '%' the basic rules are: - // (a - b) % k == 0 => a % k == b % k - // and: - // (a + b) % k == 0 => a % k == (k - b) % k + // adr = base + offset + invar + scale * iv (1) + // adr % aw = 0 (2) // - // For stride > 0 && scale > 0, - // Derive the new pre-loop limit "lim" such that the two constraints: - // (1) lim = lim0 + N (where N is some positive integer < V) - // (2) (e + lim) % V == 0 - // are true. + // Note, that we are defining the modulo operator "%" such that the remainder is + // always positive, see AlignmentSolution::mod(i, q). Since we are only computing + // modulo with powers of 2, we can instead simply use the last log2(q) bits of + // a number i, to get "i % q". This is performed with a bitmask. // - // Substituting (1) into (2), - // (e + lim0 + N) % V == 0 - // solve for N: - // N = (V - (e + lim0)) % V - // substitute back into (1), so that new limit - // lim = lim0 + (V - (e + lim0)) % V + // The limit of the pre-loop needs to be adjusted: // - // For stride > 0 && scale < 0 - // Constraints: - // lim = lim0 + N - // (e - lim) % V == 0 - // Solving for lim: - // (e - lim0 - N) % V == 0 - // N = (e - lim0) % V - // lim = lim0 + (e - lim0) % V + // old_limit: current pre-loop limit + // new_limit: new pre-loop limit + // adjust_pre_iter: additional pre-loop iterations for alignment adjustment // - // For stride < 0 && scale > 0 - // Constraints: - // lim = lim0 - N - // (e + lim) % V == 0 - // Solving for lim: - // (e + lim0 - N) % V == 0 - // N = (e + lim0) % V - // lim = lim0 - (e + lim0) % V + // We want to find adjust_pre_iter, such that the address is aligned when entering + // the main-loop: // - // For stride < 0 && scale < 0 - // Constraints: - // lim = lim0 - N - // (e - lim) % V == 0 - // Solving for lim: - // (e - lim0 + N) % V == 0 - // N = (V - (e - lim0)) % V - // lim = lim0 - (V - (e - lim0)) % V - - int vw = vector_width_in_bytes(align_to_ref); - int stride = iv_stride(); - int scale = align_to_ref_p.scale_in_bytes(); - int elt_size = align_to_ref_p.memory_size(); - int v_align = vw / elt_size; - assert(v_align > 1, "sanity"); - int offset = align_to_ref_p.offset_in_bytes() / elt_size; - Node *offsn = _igvn.intcon(offset); - - Node *e = offsn; - if (align_to_ref_p.invar() != nullptr) { - // incorporate any extra invariant piece producing (offset +/- invar) >>> log2(elt) - Node* log2_elt = _igvn.intcon(exact_log2(elt_size)); - Node* invar = align_to_ref_p.invar(); + // iv = new_limit = old_limit + adjust_pre_iter (3a, stride > 0) + // iv = new_limit = old_limit - adjust_pre_iter (3b, stride < 0) + // + // We define boi as: + // + // boi = base + offset + invar (4) + // + // And now we can simplify the address using (1), (3), and (4): + // + // adr = boi + scale * new_limit + // adr = boi + scale * (old_limit + adjust_pre_iter) (5a, stride > 0) + // adr = boi + scale * (old_limit - adjust_pre_iter) (5b, stride < 0) + // + // And hence we can restate (2) with (5), and solve the equation for adjust_pre_iter: + // + // (boi + scale * (old_limit + adjust_pre_iter) % aw = 0 (6a, stride > 0) + // (boi + scale * (old_limit - adjust_pre_iter) % aw = 0 (6b, stride < 0) + // + // In most cases, scale is the element size, for example: + // + // for (i = 0; i < a.length; i++) { a[i] = ...; } + // + // It is thus reasonable to assume that both abs(scale) and abs(stride) are + // strictly positive powers of 2. Further, they can be assumed to be non-zero, + // otherwise the address does not depend on iv, and the alignment cannot be + // affected by adjusting the pre-loop limit. + // + // Further, if abs(scale) >= aw, then adjust_pre_iter has no effect on alignment, and + // we are not able to affect the alignment at all. Hence, we require abs(scale) < aw. + // + // Moreover, for alignment to be achievable, boi must be a multiple of scale. If strict + // alignment is required (i.e. -XX:+AlignVector), this is guaranteed by the filtering + // done with the AlignmentSolver / AlignmentSolution. If strict alignment is not + // required, then alignment is still preferable for performance, but not necessary. + // In many cases boi will be a multiple of scale, but if it is not, then the adjustment + // does not guarantee alignment, but the code is still correct. + // + // Hence, in what follows we assume that boi is a multiple of scale, and in fact all + // terms in (6) are multiples of scale. Therefore we divide all terms by scale: + // + // AW = aw / abs(scale) (power of 2) (7) + // BOI = boi / abs(scale) (8) + // + // and restate (6), using (7) and (8), i.e. we divide (6) by abs(scale): + // + // (BOI + sign(scale) * (old_limit + adjust_pre_iter) % AW = 0 (9a, stride > 0) + // (BOI + sign(scale) * (old_limit - adjust_pre_iter) % AW = 0 (9b, stride < 0) + // + // where: sign(scale) = scale / abs(scale) = (scale > 0 ? 1 : -1) + // + // Note, (9) allows for periodic solutions of adjust_pre_iter, with periodicity AW. + // But we would like to spend as few iterations in the pre-loop as possible, + // hence we want the smallest adjust_pre_iter, and so: + // + // 0 <= adjust_pre_iter < AW (10) + // + // We solve (9) for adjust_pre_iter, in the following 4 cases: + // + // Case A: scale > 0 && stride > 0 (i.e. sign(scale) = 1) + // (BOI + old_limit + adjust_pre_iter) % AW = 0 + // adjust_pre_iter = (-BOI - old_limit) % AW (11a) + // + // Case B: scale < 0 && stride > 0 (i.e. sign(scale) = -1) + // (BOI - old_limit - adjust_pre_iter) % AW = 0 + // adjust_pre_iter = (BOI - old_limit) % AW (11b) + // + // Case C: scale > 0 && stride < 0 (i.e. sign(scale) = 1) + // (BOI + old_limit - adjust_pre_iter) % AW = 0 + // adjust_pre_iter = (BOI + old_limit) % AW (11c) + // + // Case D: scale < 0 && stride < 0 (i.e. sign(scale) = -1) + // (BOI - old_limit + adjust_pre_iter) % AW = 0 + // adjust_pre_iter = (-BOI + old_limit) % AW (11d) + // + // We now generalize the equations (11*) by using: + // + // OP: (stride > 0) ? SUB : ADD + // XBOI: (stride * scale > 0) ? -BOI : BOI + // + // which gives us the final pre-loop limit adjustment: + // + // adjust_pre_iter = (XBOI OP old_limit) % AW (12) + // + // We can construct XBOI by additionally defining: + // + // xboi = (stride * scale > 0) ? -boi : boi (13) + // + // which gives us: + // + // XBOI = (stride * scale > 0) ? -BOI : BOI + // = (stride * scale > 0) ? -boi / abs(scale) : boi / abs(scale) + // = xboi / abs(scale) (14) + // + // When we have computed adjust_pre_iter, we update the pre-loop limit + // with (3a, b). However, we have to make sure that the adjust_pre_iter + // additional pre-loop iterations do not lead the pre-loop to execute + // iterations that would step over the original limit (orig_limit) of + // the loop. Hence, we must constrain the updated limit as follows: + // + // constrained_limit = MIN(old_limit + adjust_pre_iter, orig_limit) + // = MIN(new_limit, orig_limit) (15a, stride > 0) + // constrained_limit = MAX(old_limit - adjust_pre_iter, orig_limit) + // = MAX(new_limit, orig_limit) (15a, stride < 0) + + // We chose an aw that is the maximal possible vector width for the type of + // align_to_ref. + const int aw = vector_width_in_bytes(align_to_ref); + const int stride = iv_stride(); + const int scale = align_to_ref_p.scale_in_bytes(); + const int offset = align_to_ref_p.offset_in_bytes(); + Node* base = align_to_ref_p.adr(); + Node* invar = align_to_ref_p.invar(); + +#ifdef ASSERT + if (is_trace_align_vector()) { + tty->print_cr("\nadjust_pre_loop_limit_to_align_main_loop_vectors:"); + tty->print(" align_to_ref:"); + align_to_ref->dump(); + tty->print_cr(" aw: %d", aw); + tty->print_cr(" stride: %d", stride); + tty->print_cr(" scale: %d", scale); + tty->print_cr(" offset: %d", offset); + tty->print(" base:"); + base->dump(); + if (invar == nullptr) { + tty->print_cr(" invar: null"); + } else { + tty->print(" invar:"); + invar->dump(); + } + tty->print(" old_limit: "); + old_limit->dump(); + tty->print(" orig_limit: "); + orig_limit->dump(); + } +#endif + + if (stride == 0 || !is_power_of_2(abs(stride)) || + scale == 0 || !is_power_of_2(abs(scale)) || + abs(scale) >= aw) { +#ifdef ASSERT + if (is_trace_align_vector()) { + tty->print_cr(" Alignment cannot be affected by changing pre-loop limit because"); + tty->print_cr(" stride or scale are not power of 2, or abs(scale) >= aw."); + } +#endif + // Cannot affect alignment, abort. + return; + } + + assert(stride != 0 && is_power_of_2(abs(stride)) && + scale != 0 && is_power_of_2(abs(scale)) && + abs(scale) < aw, "otherwise we cannot affect alignment with pre-loop"); + + const int AW = aw / abs(scale); + +#ifdef ASSERT + if (is_trace_align_vector()) { + tty->print_cr(" AW = aw(%d) / abs(scale(%d)) = %d", aw, scale, AW); + } +#endif + + // 1: Compute (13a, b): + // xboi = -boi = (-base - offset - invar) (stride * scale > 0) + // xboi = +boi = (+base + offset + invar) (stride * scale < 0) + const bool is_sub = scale * stride > 0; + + // 1.1: offset + Node* xboi = _igvn.intcon(is_sub ? -offset : offset); + TRACE_ALIGN_VECTOR_NODE(xboi); + + // 1.2: invar (if it exists) + if (invar != nullptr) { if (_igvn.type(invar)->isa_long()) { // Computations are done % (vector width/element size) so it's // safe to simply convert invar to an int and loose the upper 32 // bit half. invar = new ConvL2INode(invar); _igvn.register_new_node_with_optimizer(invar); + TRACE_ALIGN_VECTOR_NODE(invar); + } + if (is_sub) { + xboi = new SubINode(xboi, invar); + } else { + xboi = new AddINode(xboi, invar); } - Node* aref = new URShiftINode(invar, log2_elt); - _igvn.register_new_node_with_optimizer(aref); - _phase->set_ctrl(aref, pre_ctrl); - e = new AddINode(e, aref); - _igvn.register_new_node_with_optimizer(e); - _phase->set_ctrl(e, pre_ctrl); + _igvn.register_new_node_with_optimizer(xboi); + _phase->set_ctrl(xboi, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(xboi); } - if (vw > ObjectAlignmentInBytes || align_to_ref_p.base()->is_top()) { - // incorporate base e +/- base && Mask >>> log2(elt) - Node* xbase = new CastP2XNode(nullptr, align_to_ref_p.adr()); + + // 1.3: base (unless base is guaranteed aw aligned) + if (aw > ObjectAlignmentInBytes || align_to_ref_p.base()->is_top()) { + // The base is only aligned with ObjectAlignmentInBytes with arrays. + // When the base() is top, we have no alignment guarantee at all. + // Hence, we must now take the base into account for the calculation. + Node* xbase = new CastP2XNode(nullptr, base); _igvn.register_new_node_with_optimizer(xbase); + TRACE_ALIGN_VECTOR_NODE(xbase); #ifdef _LP64 xbase = new ConvL2INode(xbase); _igvn.register_new_node_with_optimizer(xbase); + TRACE_ALIGN_VECTOR_NODE(xbase); #endif - Node* mask = _igvn.intcon(vw-1); - Node* masked_xbase = new AndINode(xbase, mask); - _igvn.register_new_node_with_optimizer(masked_xbase); - Node* log2_elt = _igvn.intcon(exact_log2(elt_size)); - Node* bref = new URShiftINode(masked_xbase, log2_elt); - _igvn.register_new_node_with_optimizer(bref); - _phase->set_ctrl(bref, pre_ctrl); - e = new AddINode(e, bref); - _igvn.register_new_node_with_optimizer(e); - _phase->set_ctrl(e, pre_ctrl); - } - - // compute e +/- lim0 - if (scale < 0) { - e = new SubINode(e, lim0); + if (is_sub) { + xboi = new SubINode(xboi, xbase); + } else { + xboi = new AddINode(xboi, xbase); + } + _igvn.register_new_node_with_optimizer(xboi); + _phase->set_ctrl(xboi, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(xboi); + } + + // 2: Compute (14): + // XBOI = xboi / abs(scale) + // The division is executed as shift + Node* log2_abs_scale = _igvn.intcon(exact_log2(abs(scale))); + Node* XBOI = new URShiftINode(xboi, log2_abs_scale); + _igvn.register_new_node_with_optimizer(XBOI); + _phase->set_ctrl(XBOI, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(log2_abs_scale); + TRACE_ALIGN_VECTOR_NODE(XBOI); + + // 3: Compute (12): + // adjust_pre_iter = (XBOI OP old_limit) % AW + // + // 3.1: XBOI_OP_old_limit = XBOI OP old_limit + Node* XBOI_OP_old_limit = nullptr; + if (stride > 0) { + XBOI_OP_old_limit = new SubINode(XBOI, old_limit); } else { - e = new AddINode(e, lim0); - } - _igvn.register_new_node_with_optimizer(e); - _phase->set_ctrl(e, pre_ctrl); - - if (stride * scale > 0) { - // compute V - (e +/- lim0) - Node* va = _igvn.intcon(v_align); - e = new SubINode(va, e); - _igvn.register_new_node_with_optimizer(e); - _phase->set_ctrl(e, pre_ctrl); - } - // compute N = (exp) % V - Node* va_msk = _igvn.intcon(v_align - 1); - Node* N = new AndINode(e, va_msk); - _igvn.register_new_node_with_optimizer(N); - _phase->set_ctrl(N, pre_ctrl); - - // substitute back into (1), so that new limit - // lim = lim0 + N - Node* lim; + XBOI_OP_old_limit = new AddINode(XBOI, old_limit); + } + _igvn.register_new_node_with_optimizer(XBOI_OP_old_limit); + _phase->set_ctrl(XBOI_OP_old_limit, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(XBOI_OP_old_limit); + + // 3.2: Compute: + // adjust_pre_iter = (XBOI OP old_limit) % AW + // = XBOI_OP_old_limit % AW + // = XBOI_OP_old_limit AND (AW - 1) + // Since AW is a power of 2, the modulo operation can be replaced with + // a bitmask operation. + Node* mask_AW = _igvn.intcon(AW-1); + Node* adjust_pre_iter = new AndINode(XBOI_OP_old_limit, mask_AW); + _igvn.register_new_node_with_optimizer(adjust_pre_iter); + _phase->set_ctrl(adjust_pre_iter, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(mask_AW); + TRACE_ALIGN_VECTOR_NODE(adjust_pre_iter); + + // 4: Compute (3a, b): + // new_limit = old_limit + adjust_pre_iter (stride > 0) + // new_limit = old_limit - adjust_pre_iter (stride < 0) + Node* new_limit = nullptr; if (stride < 0) { - lim = new SubINode(lim0, N); + new_limit = new SubINode(old_limit, adjust_pre_iter); } else { - lim = new AddINode(lim0, N); - } - _igvn.register_new_node_with_optimizer(lim); - _phase->set_ctrl(lim, pre_ctrl); - Node* constrained = - (stride > 0) ? (Node*) new MinINode(lim, orig_limit) - : (Node*) new MaxINode(lim, orig_limit); - _igvn.register_new_node_with_optimizer(constrained); - _phase->set_ctrl(constrained, pre_ctrl); - _igvn.replace_input_of(pre_opaq, 1, constrained); + new_limit = new AddINode(old_limit, adjust_pre_iter); + } + _igvn.register_new_node_with_optimizer(new_limit); + _phase->set_ctrl(new_limit, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(new_limit); + + // 5: Compute (15a, b): + // Prevent pre-loop from going past the original limit of the loop. + Node* constrained_limit = + (stride > 0) ? (Node*) new MinINode(new_limit, orig_limit) + : (Node*) new MaxINode(new_limit, orig_limit); + _igvn.register_new_node_with_optimizer(constrained_limit); + _phase->set_ctrl(constrained_limit, pre_ctrl); + TRACE_ALIGN_VECTOR_NODE(constrained_limit); + + // 6: Hack the pre-loop limit + _igvn.replace_input_of(pre_opaq, 1, constrained_limit); } //------------------------------init--------------------------- diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 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/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/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/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..478cfbcb2c522 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java @@ -0,0 +1,1353 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Vanilla + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Do not force alignment. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +/* + * @test id=VerifyAlignVector + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Verify AlignVector. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+AlignVector -XX:+VerifyAlignVector + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +/* + * @test id=VerifyAlignVector-Align16 + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Verify AlignVector. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @requires vm.bits == 64 + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+AlignVector -XX:+VerifyAlignVector + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * -XX:ObjectAlignmentInBytes=16 + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +/* + * @test id=VerifyAlignVector-NoTieredCompilation-Xbatch + * @bug 8253191 + * @summary Fuzzing loops with different (random) init, limit, stride, scale etc. Verify AlignVector. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.compiler2.enabled + * @key randomness + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+AlignVector -XX:+VerifyAlignVector + * -XX:LoopUnrollLimit=250 + * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* + * -XX:-TieredCompilation -Xbatch + * compiler.loopopts.superword.TestAlignVectorFuzzer + */ + +package compiler.loopopts.superword; + +import java.lang.reflect.Array; +import java.util.Map; +import java.util.HashMap; +import java.lang.invoke.*; +import java.util.Random; +import jdk.test.lib.Utils; +import jdk.internal.misc.Unsafe; + +public class TestAlignVectorFuzzer { + static final int ITERATIONS_MAX = 5; // time allowance may lead to fewer iterations + static final int RANGE_CON = 1024 * 8; + static int ZERO = 0; + + private static final Random random = Utils.getRandomInstance(); + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + interface TestFunction { + Object[] run(); + } + + // Setup for variable compile-time constants: + private static final CallSite INIT_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite LIMIT_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite STRIDE_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite SCALE_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite OFFSET1_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite OFFSET2_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite OFFSET3_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final MethodHandle INIT_MH = INIT_CS.dynamicInvoker(); + private static final MethodHandle LIMIT_MH = LIMIT_CS.dynamicInvoker(); + private static final MethodHandle STRIDE_MH = STRIDE_CS.dynamicInvoker(); + private static final MethodHandle SCALE_MH = SCALE_CS.dynamicInvoker(); + private static final MethodHandle OFFSET1_MH = OFFSET1_CS.dynamicInvoker(); + private static final MethodHandle OFFSET2_MH = OFFSET2_CS.dynamicInvoker(); + private static final MethodHandle OFFSET3_MH = OFFSET3_CS.dynamicInvoker(); + + // Toggle if init, limit and offset are constants or variables + private static final CallSite INIT_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite LIMIT_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite OFFSET1_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite OFFSET2_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final CallSite OFFSET3_IS_CON_CS = new MutableCallSite(MethodType.methodType(boolean.class)); + private static final MethodHandle INIT_IS_CON_MH = INIT_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle LIMIT_IS_CON_MH = LIMIT_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle OFFSET1_IS_CON_MH = OFFSET1_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle OFFSET2_IS_CON_MH = OFFSET2_IS_CON_CS.dynamicInvoker(); + private static final MethodHandle OFFSET3_IS_CON_MH = OFFSET3_IS_CON_CS.dynamicInvoker(); + + // Hand-Unrolling compile-constants + private static final CallSite HAND_UNROLLING1_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite HAND_UNROLLING2_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final CallSite HAND_UNROLLING3_CS = new MutableCallSite(MethodType.methodType(int.class)); + private static final MethodHandle HAND_UNROLLING1_MH = HAND_UNROLLING1_CS.dynamicInvoker(); + private static final MethodHandle HAND_UNROLLING2_MH = HAND_UNROLLING2_CS.dynamicInvoker(); + private static final MethodHandle HAND_UNROLLING3_MH = HAND_UNROLLING3_CS.dynamicInvoker(); + + static void setConstant(CallSite cs, int value) { + MethodHandle constant = MethodHandles.constant(int.class, value); + cs.setTarget(constant); + } + + static void setConstant(CallSite cs, boolean value) { + MethodHandle constant = MethodHandles.constant(boolean.class, value); + cs.setTarget(constant); + } + + static int init_con() { // compile-time constant + try { + return (int) INIT_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean init_is_con() { // compile-time constant + try { + return (boolean) INIT_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int init_con_or_var() { + int init = init_con(); + if (!init_is_con()) { // branch constant folds to true or false + init += ZERO; // LoadI + } + return init; + } + + static int limit_con() { // compile-time constant + try { + return (int) LIMIT_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean limit_is_con() { // compile-time constant + try { + return (boolean) LIMIT_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int limit_con_or_var() { + int limit = limit_con(); + if (!limit_is_con()) { // branch constant folds to true or false + limit -= ZERO; // LoadI + } + return limit; + } + + static int stride_con() { // compile-time constant + try { + return (int) STRIDE_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int scale_con() { // compile-time constant + try { + return (int) SCALE_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset1_con() { // compile-time constant + try { + return (int) OFFSET1_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset2_con() { // compile-time constant + try { + return (int) OFFSET2_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset3_con() { // compile-time constant + try { + return (int) OFFSET3_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean offset1_is_con() { // compile-time constant + try { + return (boolean) OFFSET1_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean offset2_is_con() { // compile-time constant + try { + return (boolean) OFFSET2_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static boolean offset3_is_con() { // compile-time constant + try { + return (boolean) OFFSET3_IS_CON_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int offset1_con_or_var() { + int offset = offset1_con(); + if (!offset1_is_con()) { // branch constant folds to true or false + offset += ZERO; // LoadI + } + return offset; + } + + static int offset2_con_or_var() { + int offset = offset2_con(); + if (!offset2_is_con()) { // branch constant folds to true or false + offset += ZERO; // LoadI + } + return offset; + } + + static int offset3_con_or_var() { + int offset = offset3_con(); + if (!offset3_is_con()) { // branch constant folds to true or false + offset += ZERO; // LoadI + } + return offset; + } + + static int opposite_direction_offset1_con_or_var() { + // When indexing in the opposite direction to i, we Want to have: + // + // a[x - i * scale] + // + // So we want to fulfill these constraints: + // + // x - init * scale = offset + limit * scale + // x - limit * scale = offset + init * scale + // + // Hence: + // + // x = offset + limit * scale + init * scale; + + int offset = offset1_con_or_var(); + int init = init_con(); + int limit = limit_con(); + int scale = scale_con(); + return offset + limit * scale + init * scale; + } + + static int opposite_direction_offset2_con_or_var() { + int offset = offset2_con_or_var(); + int init = init_con(); + int limit = limit_con(); + int scale = scale_con(); + return offset + limit * scale + init * scale; + } + + static int opposite_direction_offset3_con_or_var() { + int offset = offset3_con_or_var(); + int init = init_con(); + int limit = limit_con(); + int scale = scale_con(); + return offset + limit * scale + init * scale; + } + + static int hand_unrolling1_con() { // compile-time constant + try { + return (int) HAND_UNROLLING1_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int hand_unrolling2_con() { // compile-time constant + try { + return (int) HAND_UNROLLING2_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int hand_unrolling3_con() { // compile-time constant + try { + return (int) HAND_UNROLLING3_MH.invokeExact(); + } catch (Throwable t) { + throw new InternalError(t); // should NOT happen + } + } + + static int randomStride() { + return switch (random.nextInt(6)) { + case 0 -> random.nextInt(64) + 1; // [1..64] + case 1, 2, 3 -> 1; + default -> 1 << random.nextInt(7); // powers of 2: 1..64 + }; + } + + static int randomScale() { + return switch (random.nextInt(6)) { + case 0 -> random.nextInt(64) + 1; // [1..64] + case 1, 2, 3 -> 1; + default -> 1 << random.nextInt(7); // powers of 2: 1..64 + }; + } + + static int randomOffsetDiff() { + return switch (random.nextInt(6)) { + case 0 -> random.nextInt(256) + 128; + case 1, 2, 3 -> 0; + case 4 -> +(1 << random.nextInt(8)); // powers of 2: 1..128 + default -> -(1 << random.nextInt(8)); // powers of 2: -1..-128 + }; + } + + static int randomHandUnrolling() { + return switch (random.nextInt(2)) { + case 0 -> random.nextInt(16) + 1; // [1..16] + default -> 1 << random.nextInt(5); // powers of 2: 1..16 + }; + } + + static void setRandomConstants() { + // We want to create random constants for a loop, but they should never go out of bounds. + // We constrain i to be in the range [init..limit], with init < limit. For simplicity, we + // always generate: + // + // 1 <= scale <= 64 + // 1 <= stride <= 64 + // + // We work with this reference memory access: + // + // a[offset + i * scale] + // + // It is up to the test function to re-arrange the the given terms to iterate upward or + // downward, to hand-unroll etc. + // + // We must ensure that the first and last indices are in range: + // + // 0 + error <= offset + init * scale + // offset + limit * scale < range - error + // + // The "error" term is there such that the test functions have the freedom to slightly + // diverge from the reference memory access pattern (for example modify the offset). + // + // The values for scale and range are already fixed. We now want to generate values for + // offset, init and limit. + // + // (1) Fix offset: + // + // init >= (error - offset) / scale + // limit < (range - error - offset) / scale + // + // (2) Fix init: + // + // offset >= error - init * scale + // limit < (range - error - offset) / scale + // + // (3) Fix limit: + // + // offset < range - error - limit * scale + // init >= (error - offset) / scale + // + // We can still slightly perturb the results in the direction permitted by the inequality. + + int stride = randomStride(); + int scale = randomScale(); + int range = RANGE_CON; + int error = 1024; // generous + int init; + int limit; + int offset1; + switch(random.nextInt(3)) { + case 0 -> { + offset1 = random.nextInt(2_000_000) - 1_000_000; + init = (error - offset1) / scale + random.nextInt(64); + limit = (range - error - offset1) / scale - random.nextInt(64); + } + case 1 -> { + init = random.nextInt(2_000_000) - 1_000_000; + offset1 = error - init * scale + random.nextInt(64); + limit = (range - error - offset1) / scale - random.nextInt(64); + } + default -> { + limit = random.nextInt(2_000_000) - 1_000_000; + offset1 = range - error - limit * scale - random.nextInt(64); + init = (error - offset1) / scale + random.nextInt(64); + } + } + + int offset2 = offset1 + randomOffsetDiff(); + int offset3 = offset1 + randomOffsetDiff(); + + // We can toggle the init, limit and offset to either be constant or variable: + boolean init_is_con = random.nextInt(3) != 0; + boolean limit_is_con = random.nextInt(3) != 0; + boolean offset1_is_con = random.nextInt(3) != 0; + boolean offset2_is_con = random.nextInt(3) != 0; + boolean offset3_is_con = random.nextInt(3) != 0; + + int hand_unrolling1 = randomHandUnrolling(); + int hand_unrolling2 = randomHandUnrolling(); + int hand_unrolling3 = randomHandUnrolling(); + +// Overwrite the fuzzed values below to reproduce a specific failure: +// +// init = 1; +// limit = init + 3000; +// offset1 = 0; +// offset2 = 0; +// offset3 = 32 - 2*init; +// stride = 1; +// scale = 2; +// hand_unrolling1 = 0; +// hand_unrolling2 = 0; +// hand_unrolling3 = 4; +// +// init_is_con = true; +// limit_is_con = true; +// offset1_is_con = true; +// offset2_is_con = true; +// offset3_is_con = true; + + System.out.println(" init: " + init + " (con: " + init_is_con + ")"); + System.out.println(" limit: " + limit + " (con: " + limit_is_con + ")"); + System.out.println(" offset1: " + offset1 + " (con: " + offset1_is_con + ")"); + System.out.println(" offset2: " + offset2 + " (con: " + offset2_is_con + ")"); + System.out.println(" offset3: " + offset3 + " (con: " + offset3_is_con + ")"); + System.out.println(" stride: " + stride); + System.out.println(" scale: " + scale); + System.out.println(" hand_unrolling1: " + hand_unrolling1); + System.out.println(" hand_unrolling2: " + hand_unrolling2); + System.out.println(" hand_unrolling3: " + hand_unrolling3); + setConstant(INIT_CS, init); + setConstant(LIMIT_CS, limit); + setConstant(STRIDE_CS, stride); + setConstant(SCALE_CS, scale); + setConstant(OFFSET1_CS, offset1); + setConstant(OFFSET2_CS, offset2); + setConstant(OFFSET3_CS, offset3); + setConstant(INIT_IS_CON_CS, init_is_con); + setConstant(LIMIT_IS_CON_CS, limit_is_con); + setConstant(OFFSET1_IS_CON_CS, offset1_is_con); + setConstant(OFFSET2_IS_CON_CS, offset2_is_con); + setConstant(OFFSET3_IS_CON_CS, offset3_is_con); + setConstant(HAND_UNROLLING1_CS, hand_unrolling1); + setConstant(HAND_UNROLLING2_CS, hand_unrolling2); + setConstant(HAND_UNROLLING3_CS, hand_unrolling3); + } + + public static void main(String[] args) { + byte[] aB = generateB(); + byte[] bB = generateB(); + byte[] cB = generateB(); + short[] aS = generateS(); + short[] bS = generateS(); + short[] cS = generateS(); + char[] aC = generateC(); + char[] bC = generateC(); + char[] cC = generateC(); + int[] aI = generateI(); + int[] bI = generateI(); + int[] cI = generateI(); + long[] aL = generateL(); + long[] bL = generateL(); + long[] cL = generateL(); + float[] aF = generateF(); + float[] bF = generateF(); + float[] cF = generateF(); + double[] aD = generateD(); + double[] bD = generateD(); + double[] cD = generateD(); + + // Add all tests to list + Map tests = new HashMap(); + tests.put("testUUB", () -> { return testUUB(aB.clone()); }); + tests.put("testDDB", () -> { return testDDB(aB.clone()); }); + tests.put("testUDB", () -> { return testUDB(aB.clone()); }); + tests.put("testDUB", () -> { return testDUB(aB.clone()); }); + + tests.put("testUUBH", () -> { return testUUBH(aB.clone()); }); + + tests.put("testUUBBB", () -> { return testUUBBB(aB.clone(), bB.clone(), cB.clone()); }); + tests.put("testUUBSI", () -> { return testUUBSI(aB.clone(), bS.clone(), cI.clone()); }); + + tests.put("testUUBBBH", () -> { return testUUBBBH(aB.clone(), bB.clone(), cB.clone()); }); + + tests.put("testUUBCFH", () -> { return testUUBCFH(aB.clone(), bC.clone(), cF.clone()); }); + tests.put("testDDBCFH", () -> { return testDDBCFH(aB.clone(), bC.clone(), cF.clone()); }); + tests.put("testUDBCFH", () -> { return testUDBCFH(aB.clone(), bC.clone(), cF.clone()); }); + tests.put("testDUBCFH", () -> { return testDUBCFH(aB.clone(), bC.clone(), cF.clone()); }); + + tests.put("testMMSFD", () -> { return testMMSFD(aS.clone(), bF.clone(), cD.clone()); }); + + tests.put("testUU_unsafe_BasI", () -> { return testUU_unsafe_BasI(aB.clone()); }); + tests.put("testUU_unsafe_BasIH", () -> { return testUU_unsafe_BasIH(aB.clone(), bB.clone(), cB.clone()); }); + + + // Only run for 90% of the time, and subtract some margin. This ensures the shutdown has sufficient time, + // even for very slow runs. + long test_time_allowance = System.currentTimeMillis() + + (long)(Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) * 0.9) - + 20_000; + long test_hard_timeout = System.currentTimeMillis() + + Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT); + + for (int i = 1; i <= ITERATIONS_MAX; i++) { + setRandomConstants(); + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + long allowance = test_time_allowance - System.currentTimeMillis(); + long until_timeout = test_hard_timeout - System.currentTimeMillis(); + System.out.println("ITERATION " + i + " of " + ITERATIONS_MAX + ". Test " + name + + ", time allowance: " + allowance + ", until timeout: " + until_timeout); + + // Compute gold value, probably deopt first if constants have changed. + Object[] gold = test.run(); + + // Have enough iterations to (re)compile + for (int j = 0; j < 10_000; j++) { + Object[] result = test.run(); + verify(name, gold, result); + } + + if (System.currentTimeMillis() > test_time_allowance) { + allowance = test_time_allowance - System.currentTimeMillis(); + until_timeout = test_hard_timeout - System.currentTimeMillis(); + System.out.println("TEST PASSED: hit maximal time allownance during iteration " + i + + ", time allowance: " + allowance + ", until timeout: " + until_timeout); + return; + } + } + } + long allowance = test_time_allowance - System.currentTimeMillis(); + long until_timeout = test_hard_timeout - System.currentTimeMillis(); + System.out.println("TEST PASSED, time allowance: " + allowance + ", until timeout: " + until_timeout); + } + + // Test names: + // test + // {U: i goes up, D: i goes down, M: mixed} + // {U: indexing goes up, D: indexing goes down, M: mixed} + // BSCILFD (types used) + + // -------------------- BASIC SINGLE -------------------- + + static Object[] testUUB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset + i * scale]++; + } + return new Object[]{ a }; + } + + static Object[] testDDB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + for (int i = limit; i > init; i -= stride) { + a[offset + i * scale]++; + } + return new Object[]{ a }; + } + + static Object[] testUDB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x = opposite_direction_offset1_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[x - i * scale]++; + } + return new Object[]{ a }; + } + + static Object[] testDUB(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x = opposite_direction_offset1_con_or_var(); + + for (int i = limit; i > init; i -= stride) { + a[x - i * scale]++; + } + return new Object[]{ a }; + } + + // -------------------- BASIC HAND UNROLL -------------------- + + static Object[] testUUBH(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + // All if statements with constant h fold to true or false + int h = hand_unrolling1_con(); + + for (int i = init; i < limit; i += stride) { + if (h >= 1) { a[offset + i * scale + 0]++; } + if (h >= 2) { a[offset + i * scale + 1]++; } + if (h >= 3) { a[offset + i * scale + 2]++; } + if (h >= 4) { a[offset + i * scale + 3]++; } + if (h >= 5) { a[offset + i * scale + 4]++; } + if (h >= 6) { a[offset + i * scale + 5]++; } + if (h >= 7) { a[offset + i * scale + 6]++; } + if (h >= 8) { a[offset + i * scale + 7]++; } + if (h >= 9) { a[offset + i * scale + 8]++; } + if (h >= 10) { a[offset + i * scale + 9]++; } + if (h >= 11) { a[offset + i * scale + 10]++; } + if (h >= 12) { a[offset + i * scale + 11]++; } + if (h >= 13) { a[offset + i * scale + 12]++; } + if (h >= 14) { a[offset + i * scale + 13]++; } + if (h >= 15) { a[offset + i * scale + 14]++; } + if (h >= 16) { a[offset + i * scale + 15]++; } + } + return new Object[]{ a }; + } + + // -------------------- BASIC TRIPPLE -------------------- + + static Object[] testUUBBB(byte[] a, byte[] b, byte[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset1 + i * scale]++; + b[offset2 + i * scale]++; + c[offset3 + i * scale]++; + } + return new Object[]{ a, b, c }; + } + + static Object[] testUUBSI(byte[] a, short[] b, int[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset1 + i * scale]++; + b[offset2 + i * scale]++; + c[offset3 + i * scale]++; + } + return new Object[]{ a, b, c }; + } + + // -------------------- HAND UNROLL TRIPPLE -------------------- + + static Object[] testUUBBBH(byte[] a, byte[] b, byte[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testUUBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testDDBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = limit; i > init; i -= stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testUDBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x1 = opposite_direction_offset1_con_or_var(); + int x2 = opposite_direction_offset2_con_or_var(); + int x3 = opposite_direction_offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[x1 - i * scale + 0]++; } + if (h1 >= 2) { a[x1 - i * scale + 1]++; } + if (h1 >= 3) { a[x1 - i * scale + 2]++; } + if (h1 >= 4) { a[x1 - i * scale + 3]++; } + if (h1 >= 5) { a[x1 - i * scale + 4]++; } + if (h1 >= 6) { a[x1 - i * scale + 5]++; } + if (h1 >= 7) { a[x1 - i * scale + 6]++; } + if (h1 >= 8) { a[x1 - i * scale + 7]++; } + if (h1 >= 9) { a[x1 - i * scale + 8]++; } + if (h1 >= 10) { a[x1 - i * scale + 9]++; } + if (h1 >= 11) { a[x1 - i * scale + 10]++; } + if (h1 >= 12) { a[x1 - i * scale + 11]++; } + if (h1 >= 13) { a[x1 - i * scale + 12]++; } + if (h1 >= 14) { a[x1 - i * scale + 13]++; } + if (h1 >= 15) { a[x1 - i * scale + 14]++; } + if (h1 >= 16) { a[x1 - i * scale + 15]++; } + + if (h2 >= 1) { b[x2 - i * scale + 0]++; } + if (h2 >= 2) { b[x2 - i * scale + 1]++; } + if (h2 >= 3) { b[x2 - i * scale + 2]++; } + if (h2 >= 4) { b[x2 - i * scale + 3]++; } + if (h2 >= 5) { b[x2 - i * scale + 4]++; } + if (h2 >= 6) { b[x2 - i * scale + 5]++; } + if (h2 >= 7) { b[x2 - i * scale + 6]++; } + if (h2 >= 8) { b[x2 - i * scale + 7]++; } + if (h2 >= 9) { b[x2 - i * scale + 8]++; } + if (h2 >= 10) { b[x2 - i * scale + 9]++; } + if (h2 >= 11) { b[x2 - i * scale + 10]++; } + if (h2 >= 12) { b[x2 - i * scale + 11]++; } + if (h2 >= 13) { b[x2 - i * scale + 12]++; } + if (h2 >= 14) { b[x2 - i * scale + 13]++; } + if (h2 >= 15) { b[x2 - i * scale + 14]++; } + if (h2 >= 16) { b[x2 - i * scale + 15]++; } + + if (h3 >= 1) { c[x3 - i * scale + 0]++; } + if (h3 >= 2) { c[x3 - i * scale + 1]++; } + if (h3 >= 3) { c[x3 - i * scale + 2]++; } + if (h3 >= 4) { c[x3 - i * scale + 3]++; } + if (h3 >= 5) { c[x3 - i * scale + 4]++; } + if (h3 >= 6) { c[x3 - i * scale + 5]++; } + if (h3 >= 7) { c[x3 - i * scale + 6]++; } + if (h3 >= 8) { c[x3 - i * scale + 7]++; } + if (h3 >= 9) { c[x3 - i * scale + 8]++; } + if (h3 >= 10) { c[x3 - i * scale + 9]++; } + if (h3 >= 11) { c[x3 - i * scale + 10]++; } + if (h3 >= 12) { c[x3 - i * scale + 11]++; } + if (h3 >= 13) { c[x3 - i * scale + 12]++; } + if (h3 >= 14) { c[x3 - i * scale + 13]++; } + if (h3 >= 15) { c[x3 - i * scale + 14]++; } + if (h3 >= 16) { c[x3 - i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + static Object[] testDUBCFH(byte[] a, char[] b, float[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int x1 = opposite_direction_offset1_con_or_var(); + int x2 = opposite_direction_offset2_con_or_var(); + int x3 = opposite_direction_offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = limit; i > init; i -= stride) { + if (h1 >= 1) { a[x1 - i * scale + 0]++; } + if (h1 >= 2) { a[x1 - i * scale + 1]++; } + if (h1 >= 3) { a[x1 - i * scale + 2]++; } + if (h1 >= 4) { a[x1 - i * scale + 3]++; } + if (h1 >= 5) { a[x1 - i * scale + 4]++; } + if (h1 >= 6) { a[x1 - i * scale + 5]++; } + if (h1 >= 7) { a[x1 - i * scale + 6]++; } + if (h1 >= 8) { a[x1 - i * scale + 7]++; } + if (h1 >= 9) { a[x1 - i * scale + 8]++; } + if (h1 >= 10) { a[x1 - i * scale + 9]++; } + if (h1 >= 11) { a[x1 - i * scale + 10]++; } + if (h1 >= 12) { a[x1 - i * scale + 11]++; } + if (h1 >= 13) { a[x1 - i * scale + 12]++; } + if (h1 >= 14) { a[x1 - i * scale + 13]++; } + if (h1 >= 15) { a[x1 - i * scale + 14]++; } + if (h1 >= 16) { a[x1 - i * scale + 15]++; } + + if (h2 >= 1) { b[x2 - i * scale + 0]++; } + if (h2 >= 2) { b[x2 - i * scale + 1]++; } + if (h2 >= 3) { b[x2 - i * scale + 2]++; } + if (h2 >= 4) { b[x2 - i * scale + 3]++; } + if (h2 >= 5) { b[x2 - i * scale + 4]++; } + if (h2 >= 6) { b[x2 - i * scale + 5]++; } + if (h2 >= 7) { b[x2 - i * scale + 6]++; } + if (h2 >= 8) { b[x2 - i * scale + 7]++; } + if (h2 >= 9) { b[x2 - i * scale + 8]++; } + if (h2 >= 10) { b[x2 - i * scale + 9]++; } + if (h2 >= 11) { b[x2 - i * scale + 10]++; } + if (h2 >= 12) { b[x2 - i * scale + 11]++; } + if (h2 >= 13) { b[x2 - i * scale + 12]++; } + if (h2 >= 14) { b[x2 - i * scale + 13]++; } + if (h2 >= 15) { b[x2 - i * scale + 14]++; } + if (h2 >= 16) { b[x2 - i * scale + 15]++; } + + if (h3 >= 1) { c[x3 - i * scale + 0]++; } + if (h3 >= 2) { c[x3 - i * scale + 1]++; } + if (h3 >= 3) { c[x3 - i * scale + 2]++; } + if (h3 >= 4) { c[x3 - i * scale + 3]++; } + if (h3 >= 5) { c[x3 - i * scale + 4]++; } + if (h3 >= 6) { c[x3 - i * scale + 5]++; } + if (h3 >= 7) { c[x3 - i * scale + 6]++; } + if (h3 >= 8) { c[x3 - i * scale + 7]++; } + if (h3 >= 9) { c[x3 - i * scale + 8]++; } + if (h3 >= 10) { c[x3 - i * scale + 9]++; } + if (h3 >= 11) { c[x3 - i * scale + 10]++; } + if (h3 >= 12) { c[x3 - i * scale + 11]++; } + if (h3 >= 13) { c[x3 - i * scale + 12]++; } + if (h3 >= 14) { c[x3 - i * scale + 13]++; } + if (h3 >= 15) { c[x3 - i * scale + 14]++; } + if (h3 >= 16) { c[x3 - i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } + + // -------------------- MIXED DIRECTION TRIPPLE -------------------- + + static Object[] testMMSFD(short[] a, float[] b, double[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = opposite_direction_offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + for (int i = init; i < limit; i += stride) { + a[offset1 + i * scale]++; + b[offset2 - i * scale]++; + c[offset3 + i * scale]++; + } + return new Object[]{ a, b, c }; + } + + // -------------------- UNSAFE -------------------- + + static Object[] testUU_unsafe_BasI(byte[] a) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset = offset1_con_or_var(); + + for (int i = init; i < limit; i += stride) { + int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale; + int v = UNSAFE.getIntUnaligned(a, adr); + UNSAFE.putIntUnaligned(a, adr, v + 1); + } + return new Object[]{ a }; + } + + static Object[] testUU_unsafe_BasIH(byte[] a, byte[] b, byte[] c) { + int init = init_con_or_var(); + int limit = limit_con_or_var(); + int stride = stride_con(); + int scale = scale_con(); + int offset1 = offset1_con_or_var(); + int offset2 = offset2_con_or_var(); + int offset3 = offset3_con_or_var(); + + int h1 = hand_unrolling1_con(); + int h2 = hand_unrolling2_con(); + int h3 = hand_unrolling3_con(); + + for (int i = init; i < limit; i += stride) { + int adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale; + int adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale; + int adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale; + + if (h1 >= 1) { UNSAFE.putIntUnaligned(a, adr1 + 0*4, UNSAFE.getIntUnaligned(a, adr1 + 0*4) + 1); } + if (h1 >= 2) { UNSAFE.putIntUnaligned(a, adr1 + 1*4, UNSAFE.getIntUnaligned(a, adr1 + 1*4) + 1); } + if (h1 >= 3) { UNSAFE.putIntUnaligned(a, adr1 + 2*4, UNSAFE.getIntUnaligned(a, adr1 + 2*4) + 1); } + if (h1 >= 4) { UNSAFE.putIntUnaligned(a, adr1 + 3*4, UNSAFE.getIntUnaligned(a, adr1 + 3*4) + 1); } + if (h1 >= 5) { UNSAFE.putIntUnaligned(a, adr1 + 4*4, UNSAFE.getIntUnaligned(a, adr1 + 4*4) + 1); } + if (h1 >= 6) { UNSAFE.putIntUnaligned(a, adr1 + 5*4, UNSAFE.getIntUnaligned(a, adr1 + 5*4) + 1); } + if (h1 >= 7) { UNSAFE.putIntUnaligned(a, adr1 + 6*4, UNSAFE.getIntUnaligned(a, adr1 + 6*4) + 1); } + if (h1 >= 8) { UNSAFE.putIntUnaligned(a, adr1 + 7*4, UNSAFE.getIntUnaligned(a, adr1 + 7*4) + 1); } + if (h1 >= 9) { UNSAFE.putIntUnaligned(a, adr1 + 8*4, UNSAFE.getIntUnaligned(a, adr1 + 8*4) + 1); } + if (h1 >= 10) { UNSAFE.putIntUnaligned(a, adr1 + 9*4, UNSAFE.getIntUnaligned(a, adr1 + 9*4) + 1); } + if (h1 >= 11) { UNSAFE.putIntUnaligned(a, adr1 + 10*4, UNSAFE.getIntUnaligned(a, adr1 + 10*4) + 1); } + if (h1 >= 12) { UNSAFE.putIntUnaligned(a, adr1 + 11*4, UNSAFE.getIntUnaligned(a, adr1 + 11*4) + 1); } + if (h1 >= 13) { UNSAFE.putIntUnaligned(a, adr1 + 12*4, UNSAFE.getIntUnaligned(a, adr1 + 12*4) + 1); } + if (h1 >= 14) { UNSAFE.putIntUnaligned(a, adr1 + 13*4, UNSAFE.getIntUnaligned(a, adr1 + 13*4) + 1); } + if (h1 >= 15) { UNSAFE.putIntUnaligned(a, adr1 + 14*4, UNSAFE.getIntUnaligned(a, adr1 + 14*4) + 1); } + if (h1 >= 16) { UNSAFE.putIntUnaligned(a, adr1 + 15*4, UNSAFE.getIntUnaligned(a, adr1 + 15*4) + 1); } + + if (h2 >= 1) { UNSAFE.putIntUnaligned(b, adr2 + 0*4, UNSAFE.getIntUnaligned(b, adr2 + 0*4) + 1); } + if (h2 >= 2) { UNSAFE.putIntUnaligned(b, adr2 + 1*4, UNSAFE.getIntUnaligned(b, adr2 + 1*4) + 1); } + if (h2 >= 3) { UNSAFE.putIntUnaligned(b, adr2 + 2*4, UNSAFE.getIntUnaligned(b, adr2 + 2*4) + 1); } + if (h2 >= 4) { UNSAFE.putIntUnaligned(b, adr2 + 3*4, UNSAFE.getIntUnaligned(b, adr2 + 3*4) + 1); } + if (h2 >= 5) { UNSAFE.putIntUnaligned(b, adr2 + 4*4, UNSAFE.getIntUnaligned(b, adr2 + 4*4) + 1); } + if (h2 >= 6) { UNSAFE.putIntUnaligned(b, adr2 + 5*4, UNSAFE.getIntUnaligned(b, adr2 + 5*4) + 1); } + if (h2 >= 7) { UNSAFE.putIntUnaligned(b, adr2 + 6*4, UNSAFE.getIntUnaligned(b, adr2 + 6*4) + 1); } + if (h2 >= 8) { UNSAFE.putIntUnaligned(b, adr2 + 7*4, UNSAFE.getIntUnaligned(b, adr2 + 7*4) + 1); } + if (h2 >= 9) { UNSAFE.putIntUnaligned(b, adr2 + 8*4, UNSAFE.getIntUnaligned(b, adr2 + 8*4) + 1); } + if (h2 >= 10) { UNSAFE.putIntUnaligned(b, adr2 + 9*4, UNSAFE.getIntUnaligned(b, adr2 + 9*4) + 1); } + if (h2 >= 11) { UNSAFE.putIntUnaligned(b, adr2 + 10*4, UNSAFE.getIntUnaligned(b, adr2 + 10*4) + 1); } + if (h2 >= 12) { UNSAFE.putIntUnaligned(b, adr2 + 11*4, UNSAFE.getIntUnaligned(b, adr2 + 11*4) + 1); } + if (h2 >= 13) { UNSAFE.putIntUnaligned(b, adr2 + 12*4, UNSAFE.getIntUnaligned(b, adr2 + 12*4) + 1); } + if (h2 >= 14) { UNSAFE.putIntUnaligned(b, adr2 + 13*4, UNSAFE.getIntUnaligned(b, adr2 + 13*4) + 1); } + if (h2 >= 15) { UNSAFE.putIntUnaligned(b, adr2 + 14*4, UNSAFE.getIntUnaligned(b, adr2 + 14*4) + 1); } + if (h2 >= 16) { UNSAFE.putIntUnaligned(b, adr2 + 15*4, UNSAFE.getIntUnaligned(b, adr2 + 15*4) + 1); } + + if (h3 >= 1) { UNSAFE.putIntUnaligned(c, adr3 + 0*4, UNSAFE.getIntUnaligned(c, adr3 + 0*4) + 1); } + if (h3 >= 2) { UNSAFE.putIntUnaligned(c, adr3 + 1*4, UNSAFE.getIntUnaligned(c, adr3 + 1*4) + 1); } + if (h3 >= 3) { UNSAFE.putIntUnaligned(c, adr3 + 2*4, UNSAFE.getIntUnaligned(c, adr3 + 2*4) + 1); } + if (h3 >= 4) { UNSAFE.putIntUnaligned(c, adr3 + 3*4, UNSAFE.getIntUnaligned(c, adr3 + 3*4) + 1); } + if (h3 >= 5) { UNSAFE.putIntUnaligned(c, adr3 + 4*4, UNSAFE.getIntUnaligned(c, adr3 + 4*4) + 1); } + if (h3 >= 6) { UNSAFE.putIntUnaligned(c, adr3 + 5*4, UNSAFE.getIntUnaligned(c, adr3 + 5*4) + 1); } + if (h3 >= 7) { UNSAFE.putIntUnaligned(c, adr3 + 6*4, UNSAFE.getIntUnaligned(c, adr3 + 6*4) + 1); } + if (h3 >= 8) { UNSAFE.putIntUnaligned(c, adr3 + 7*4, UNSAFE.getIntUnaligned(c, adr3 + 7*4) + 1); } + if (h3 >= 9) { UNSAFE.putIntUnaligned(c, adr3 + 8*4, UNSAFE.getIntUnaligned(c, adr3 + 8*4) + 1); } + if (h3 >= 10) { UNSAFE.putIntUnaligned(c, adr3 + 9*4, UNSAFE.getIntUnaligned(c, adr3 + 9*4) + 1); } + if (h3 >= 11) { UNSAFE.putIntUnaligned(c, adr3 + 10*4, UNSAFE.getIntUnaligned(c, adr3 + 10*4) + 1); } + if (h3 >= 12) { UNSAFE.putIntUnaligned(c, adr3 + 11*4, UNSAFE.getIntUnaligned(c, adr3 + 11*4) + 1); } + if (h3 >= 13) { UNSAFE.putIntUnaligned(c, adr3 + 12*4, UNSAFE.getIntUnaligned(c, adr3 + 12*4) + 1); } + if (h3 >= 14) { UNSAFE.putIntUnaligned(c, adr3 + 13*4, UNSAFE.getIntUnaligned(c, adr3 + 13*4) + 1); } + if (h3 >= 15) { UNSAFE.putIntUnaligned(c, adr3 + 14*4, UNSAFE.getIntUnaligned(c, adr3 + 14*4) + 1); } + if (h3 >= 16) { UNSAFE.putIntUnaligned(c, adr3 + 15*4, UNSAFE.getIntUnaligned(c, adr3 + 15*4) + 1); } + } + return new Object[]{ a, b, c }; + } + + static byte[] generateB() { + byte[] a = new byte[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (byte)random.nextInt(); + } + return a; + } + + static char[] generateC() { + char[] a = new char[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (char)random.nextInt(); + } + return a; + } + + static short[] generateS() { + short[] a = new short[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (short)random.nextInt(); + } + return a; + } + + static int[] generateI() { + int[] a = new int[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = random.nextInt(); + } + return a; + } + + static long[] generateL() { + long[] a = new long[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = random.nextLong(); + } + return a; + } + + static float[] generateF() { + float[] a = new float[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = Float.intBitsToFloat(random.nextInt()); + } + return a; + } + + static double[] generateD() { + double[] a = new double[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = Double.longBitsToDouble(random.nextLong()); + } + return a; + } + + static void verify(String name, Object[] gold, Object[] result) { + if (gold.length != result.length) { + throw new RuntimeException("verify " + name + ": not the same number of outputs: gold.length = " + + gold.length + ", result.length = " + result.length); + } + for (int i = 0; i < gold.length; i++) { + Object g = gold[i]; + Object r = result[i]; + if (g.getClass() != r.getClass() || !g.getClass().isArray() || !r.getClass().isArray()) { + throw new RuntimeException("verify " + name + ": must both be array of same type:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + if (g == r) { + throw new RuntimeException("verify " + name + ": should be two separate arrays (with identical content):" + + " gold[" + i + "] == result[" + i + "]"); + } + if (Array.getLength(g) != Array.getLength(r)) { + throw new RuntimeException("verify " + name + ": arrays must have same length:" + + " gold[" + i + "].length = " + Array.getLength(g) + + " result[" + i + "].length = " + Array.getLength(r)); + } + Class c = g.getClass().getComponentType(); + if (c == byte.class) { + verifyB(name, i, (byte[])g, (byte[])r); + } else if (c == char.class) { + verifyC(name, i, (char[])g, (char[])r); + } else if (c == short.class) { + verifyS(name, i, (short[])g, (short[])r); + } else if (c == int.class) { + verifyI(name, i, (int[])g, (int[])r); + } else if (c == long.class) { + verifyL(name, i, (long[])g, (long[])r); + } else if (c == float.class) { + verifyF(name, i, (float[])g, (float[])r); + } else if (c == double.class) { + verifyD(name, i, (double[])g, (double[])r); + } else { + throw new RuntimeException("verify " + name + ": array type not supported for verify:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + } + } + + static void verifyB(String name, int i, byte[] g, byte[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyB " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyC(String name, int i, char[] g, char[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyC " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyS(String name, int i, short[] g, short[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyS " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyI(String name, int i, int[] g, int[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyI " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyL(String name, int i, long[] g, long[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verifyL " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyF(String name, int i, float[] g, float[] r) { + for (int j = 0; j < g.length; j++) { + int gv = UNSAFE.getInt(g, UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4 * j); + int rv = UNSAFE.getInt(r, UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4 * j); + if (gv != rv) { + throw new RuntimeException("verifyF " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + gv + + " result[" + i + "][" + j + "] = " + rv); + } + } + } + + static void verifyD(String name, int i, double[] g, double[] r) { + for (int j = 0; j < g.length; j++) { + long gv = UNSAFE.getLong(g, UNSAFE.ARRAY_DOUBLE_BASE_OFFSET + 8 * j); + long rv = UNSAFE.getLong(r, UNSAFE.ARRAY_DOUBLE_BASE_OFFSET + 8 * j); + if (gv != rv) { + throw new RuntimeException("verifyF " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + gv + + " result[" + i + "][" + j + "] = " + rv); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index 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/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); + } } } From c4a83bd6f6c45e72bd776e929005be0aa9408867 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Mon, 8 Jan 2024 16:44:28 +0000 Subject: [PATCH 015/153] 8323086: Shenandoah: Heap could be corrupted by oom during evacuation Reviewed-by: kdnilsen, shade --- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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, From 387828a3f7e4ec5b26954747e756aac212d579ae Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 8 Jan 2024 16:56:44 +0000 Subject: [PATCH 016/153] 8322980: Debug agent's dumpThread() API should update thread's name before printing it Reviewed-by: kevinw, sspitsyn --- .../share/native/libjdwp/threadControl.c | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 581de4305713e..5628f8b44db43 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -2623,15 +2623,58 @@ dumpThreadList(ThreadList *list) } } +#ifdef DEBUG_THREADNAME +static void +setThreadName(ThreadNode *node) +{ + /* + * Sometimes the debuggee changes the thread name, so we need to fetch + * and set it again. + */ + jvmtiThreadInfo info; + jvmtiError error; + + memset(&info, 0, sizeof(info)); + error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, node->thread, &info); + if (info.name != NULL) { + strncpy(node->name, info.name, sizeof(node->name) - 1); + jvmtiDeallocate(info.name); + } +} +#endif + +#if 0 +static jint +getThreadState(ThreadNode *node) +{ + jint state = 0; + jvmtiError error = FUNC_PTR(gdata->jvmti,GetThreadState) + (gdata->jvmti, node->thread, &state); + return state; +} +#endif + static void dumpThread(ThreadNode *node) { - tty_message(" Thread: node = %p, jthread = %p", node, node->thread); + tty_message("Thread: node = %p, jthread = %p", node, node->thread); #ifdef DEBUG_THREADNAME + setThreadName(node); tty_message("\tname: %s", node->name); #endif // More fields can be printed here when needed. The amount of output is intentionally // kept small so it doesn't generate too much output. tty_message("\tsuspendCount: %d", node->suspendCount); +#if 0 + tty_message("\tsuspendAllCount: %d", suspendAllCount); + tty_message("\tthreadState: 0x%x", getThreadState(node)); + tty_message("\ttoBeResumed: %d", node->toBeResumed); + tty_message("\tis_vthread: %d", node->is_vthread); + tty_message("\tcurrentInvoke.pending: %d", node->currentInvoke.pending); + tty_message("\tcurrentInvoke.started: %d", node->currentInvoke.started); + tty_message("\tcurrentInvoke.available: %d", node->currentInvoke.available); + tty_message("\tobjID: %d", commonRef_refToID(getEnv(), node->thread)); +#endif } #endif /* DEBUG */ From d47393bd8225e818f0f9cd45192a5e656018af11 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Mon, 8 Jan 2024 18:53:41 +0000 Subject: [PATCH 017/153] 8320128: Clean up Parse constructor for OSR Reviewed-by: thartmann, shade --- src/hotspot/share/opto/parse.hpp | 7 +++-- src/hotspot/share/opto/parse1.cpp | 47 +++++++++++++++---------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 72929729812d1..40314ecc29d67 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -416,8 +416,11 @@ class Parse : public GraphKit { void set_block(Block* b) { _block = b; } // Derived accessors: - bool is_normal_parse() const { return _entry_bci == InvocationEntryBci; } - bool is_osr_parse() const { return _entry_bci != InvocationEntryBci; } + bool is_osr_parse() const { + assert(_entry_bci != UnknownBci, "uninitialized _entry_bci"); + return _entry_bci != InvocationEntryBci; + } + bool is_normal_parse() const { return !is_osr_parse(); } int osr_bci() const { assert(is_osr_parse(),""); return _entry_bci; } void set_parse_bci(int bci); diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 96db18f774fe7..c1fe7acaa75a3 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -401,19 +401,17 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) _wrote_stable = false; _wrote_fields = false; _alloc_with_final = nullptr; - _entry_bci = InvocationEntryBci; - _tf = nullptr; _block = nullptr; _first_return = true; _replaced_nodes_for_exceptions = false; _new_idx = C->unique(); - debug_only(_block_count = -1); - debug_only(_blocks = (Block*)-1); + DEBUG_ONLY(_entry_bci = UnknownBci); + DEBUG_ONLY(_block_count = -1); + DEBUG_ONLY(_blocks = (Block*)-1); #ifndef PRODUCT if (PrintCompilation || PrintOpto) { // Make sure I have an inline tree, so I can print messages about it. - JVMState* ilt_caller = is_osr_parse() ? caller->caller() : caller; - InlineTree::find_subtree_from_root(C->ilt(), ilt_caller, parse_method); + InlineTree::find_subtree_from_root(C->ilt(), caller, parse_method); } _max_switch_depth = 0; _est_switch_depth = 0; @@ -427,19 +425,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) C->set_has_monitors(true); } - _tf = TypeFunc::make(method()); _iter.reset_to_method(method()); - _flow = method()->get_flow_analysis(); - if (_flow->failing()) { - assert(false, "type flow failed during parsing"); - C->record_method_not_compilable(_flow->failure_reason()); - } - -#ifndef PRODUCT - if (_flow->has_irreducible_entry()) { - C->set_parsed_irreducible_loop(true); - } -#endif C->set_has_loops(C->has_loops() || method()->has_loops()); if (_expected_uses <= 0) { @@ -507,14 +493,25 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) // Do some special top-level things. if (depth() == 1 && C->is_osr_compilation()) { + _tf = C->tf(); // the OSR entry type is different _entry_bci = C->entry_bci(); _flow = method()->get_osr_flow_analysis(osr_bci()); - if (_flow->failing()) { - 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(); @@ -522,8 +519,6 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) } } #endif - } - _tf = C->tf(); // the OSR entry type is different } #ifdef ASSERT @@ -535,6 +530,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) #endif #ifndef PRODUCT + if (_flow->has_irreducible_entry()) { + C->set_parsed_irreducible_loop(true); + } + methods_parsed++; // add method size here to guarantee that inlined methods are added too if (CITime) From 24823ba647d4bf412586372cd5076f35bbc131a5 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Mon, 8 Jan 2024 19:46:04 +0000 Subject: [PATCH 018/153] 8323095: Expand TraceOptoParse block output abbreviations Reviewed-by: thartmann, chagedorn, xliu --- src/hotspot/share/opto/parse1.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index c1fe7acaa75a3..8ee99ae9a65e3 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1511,13 +1511,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"); From d78e8dab93868c1212c95e165f556ad89a0b6920 Mon Sep 17 00:00:00 2001 From: Rajat Mahajan Date: Mon, 8 Jan 2024 19:58:32 +0000 Subject: [PATCH 019/153] 8322545: Declare newInsets as static in ThemeReader.cpp Reviewed-by: serb, aivanov --- .../windows/native/libawt/windows/ThemeReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; } From 8a4dc79e1a40e7115e2971af81623b6b0368f41c Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Mon, 8 Jan 2024 20:17:29 +0000 Subject: [PATCH 020/153] 8274300: Address dsymutil warning by excluding platform specific files Reviewed-by: erikj --- make/test/BuildTestLibNative.gmk | 6 +++++- make/test/JtregNativeHotspot.gmk | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) 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) From ca9635df3357bf70b41645f619237b6d2068afb7 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 8 Jan 2024 21:26:18 +0000 Subject: [PATCH 021/153] 8322759: Eliminate -Wparentheses warnings in compiler code Reviewed-by: kvn, shade --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 10 +++++----- src/hotspot/share/c1/c1_LinearScan.cpp | 6 +++--- src/hotspot/share/c1/c1_ValueStack.hpp | 4 ++-- src/hotspot/share/code/relocInfo.cpp | 6 +++--- .../share/compiler/compilerDefinitions.inline.hpp | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index fe9a8a478365d..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"); } } } 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/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/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(); } From 61ebe3b0c4afb6bfdadbf54d0e8a20347bea1975 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 8 Jan 2024 22:41:07 +0000 Subject: [PATCH 022/153] 8323032: OptimizedModuleHandlingTest failed in dynamic CDS archive mode Reviewed-by: dholmes, matsaave --- test/hotspot/jtreg/ProblemList.txt | 1 - .../OptimizeModuleHandlingTest.java | 34 +++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f6913a0734ddc..d82f4a919fa81 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -113,7 +113,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/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); }); + } } } From 841ab487f83d7e3639d352e796dc7131310c2390 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 8 Jan 2024 23:53:06 +0000 Subject: [PATCH 023/153] 8322657: CDS filemap fastdebug assert while loading Graal CE Polyglot in isolated classloader Reviewed-by: matsaave, dholmes --- src/hotspot/share/cds/filemap.cpp | 16 +-- src/hotspot/share/cds/filemap.hpp | 3 +- .../jtreg/runtime/cds/appcds/JarBuilder.java | 19 +++- .../ModularJarWithNonExistentJar.java | 105 ++++++++++++++++++ .../test-classes/DefineModuleApp.java | 51 +++++++++ .../manifest-with-non-existent-jar.txt | 3 + 6 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt 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/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) From 8ae309ebacd6947bbad2ef168ca13702e1cba099 Mon Sep 17 00:00:00 2001 From: Weibing Xiao Date: Tue, 9 Jan 2024 04:04:12 +0000 Subject: [PATCH 024/153] 8318971: Better Error Handling for Jar Tool When Processing Non-existent Files Reviewed-by: alanb, jpai --- .../share/classes/sun/tools/jar/Main.java | 6 ++ test/jdk/tools/jar/InputFilesTest.java | 82 ++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index fce80372b1e27..6163ef8264772 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -292,6 +292,9 @@ public synchronized boolean run(String args[]) { } } expand(); + if (!ok) { + return false; + } if (!moduleInfos.isEmpty()) { // All actual file entries (excl manifest and module-info.class) Set jentries = new HashSet<>(); @@ -338,6 +341,9 @@ public synchronized boolean run(String args[]) { tmpFile = createTemporaryFile("tmpjar", ".jar"); } expand(); + if (!ok) { + return false; + } try (FileInputStream in = (fname != null) ? new FileInputStream(inputFile) : new FileInputStream(FileDescriptor.in); FileOutputStream out = new FileOutputStream(tmpFile); 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("/"))); } From 176606d0cb9117ca9080261f898cd57339fa5a85 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 9 Jan 2024 04:36:30 +0000 Subject: [PATCH 025/153] 8310995: missing @since tags in 36 jdk.dynalink classes Reviewed-by: jlaskey, iris, attila --- .../share/classes/jdk/dynalink/CallSiteDescriptor.java | 1 + src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java | 1 + .../share/classes/jdk/dynalink/DynamicLinkerFactory.java | 1 + src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java | 1 + src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java | 1 + .../share/classes/jdk/dynalink/NamespaceOperation.java | 1 + .../classes/jdk/dynalink/NoSuchDynamicMethodException.java | 1 + src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java | 1 + .../share/classes/jdk/dynalink/RelinkableCallSite.java | 1 + .../share/classes/jdk/dynalink/SecureLookupSupplier.java | 1 + .../share/classes/jdk/dynalink/StandardNamespace.java | 1 + .../share/classes/jdk/dynalink/StandardOperation.java | 1 + .../share/classes/jdk/dynalink/beans/BeansLinker.java | 1 + .../classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java | 1 + .../share/classes/jdk/dynalink/beans/StaticClass.java | 1 + .../share/classes/jdk/dynalink/linker/ConversionComparator.java | 2 ++ .../share/classes/jdk/dynalink/linker/GuardedInvocation.java | 1 + .../jdk/dynalink/linker/GuardedInvocationTransformer.java | 1 + .../classes/jdk/dynalink/linker/GuardingDynamicLinker.java | 1 + .../jdk/dynalink/linker/GuardingDynamicLinkerExporter.java | 1 + .../jdk/dynalink/linker/GuardingTypeConverterFactory.java | 1 + .../share/classes/jdk/dynalink/linker/LinkRequest.java | 1 + .../share/classes/jdk/dynalink/linker/LinkerServices.java | 1 + .../classes/jdk/dynalink/linker/MethodHandleTransformer.java | 1 + .../jdk/dynalink/linker/MethodTypeConversionStrategy.java | 1 + .../jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java | 1 + .../dynalink/linker/support/CompositeGuardingDynamicLinker.java | 1 + .../linker/support/CompositeTypeBasedGuardingDynamicLinker.java | 1 + .../dynalink/linker/support/DefaultInternalObjectFilter.java | 1 + .../share/classes/jdk/dynalink/linker/support/Guards.java | 1 + .../share/classes/jdk/dynalink/linker/support/Lookup.java | 1 + .../classes/jdk/dynalink/linker/support/SimpleLinkRequest.java | 1 + .../classes/jdk/dynalink/linker/support/TypeUtilities.java | 1 + src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java | 1 + .../jdk/dynalink/support/AbstractRelinkableCallSite.java | 1 + .../share/classes/jdk/dynalink/support/ChainedCallSite.java | 1 + .../classes/jdk/dynalink/support/SimpleRelinkableCallSite.java | 1 + 37 files changed, 38 insertions(+) diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java index e1e49f22b4c45..e47625fb497d5 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java @@ -88,6 +88,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * the {@code MethodHandles.Lookup} object it carries. This lookup should be used * to find method handles to set as targets of the call site described by this * descriptor. + * @since 9 */ public class CallSiteDescriptor extends SecureLookupSupplier { private final Operation operation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java index eb7de0aba75a1..23f4f7a81227c 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java @@ -141,6 +141,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * in the above example the {@code parseOperation} method is left unimplemented. * * + * @since 9 */ public final class DynamicLinker { private static final String CLASS_NAME = DynamicLinker.class.getName(); diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java index a34cff5ba12fe..ed2110085669f 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java @@ -105,6 +105,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and * finally the ones configured with {@link #setFallbackLinkers(List)}; this last * category usually includes {@link BeansLinker}. + * @since 9 */ public final class DynamicLinkerFactory { @SuppressWarnings("removal") diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java index 7563e3946ad96..5fe3e96f43ec4 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java @@ -106,6 +106,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * usually containing the textual representation of the source expression that retrieved the * callee, e.g. {@code StandardOperation.CALL.named("window.open")}. *

+ * @since 9 */ public final class NamedOperation implements Operation { private final Operation baseOperation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java index 69b68d25ffc3a..8f5e7ede7f639 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java @@ -66,6 +66,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * set of standard namespaces with the {@link StandardNamespace} enum. Operations * that need to specify a namespace they operate on can be expressed using * {@link NamespaceOperation}. + * @since 9 */ public interface Namespace { } diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java index 322767de36463..0e047849c2c52 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java @@ -134,6 +134,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * StandardNamespace.PROPERTY) * .named("empty"); * + * @since 9 */ public final class NamespaceOperation implements Operation { private final Operation baseOperation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java index bf20c23b7380d..8842c32c1befc 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java @@ -64,6 +64,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Thrown at the invocation if the call site can not be linked by any available {@link GuardingDynamicLinker}. + * @since 9 */ public class NoSuchDynamicMethodException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java index ba22e32c54f3a..ef0acbc3b5741 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java @@ -74,6 +74,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@code GET:PROPERTY|ELEMENT}), and finally we will refer to named operations * by separating the base operation and the name with the colon character (e.g. * {@code GET:PROPERTY|ELEMENT:color}). + * @since 9 */ public interface Operation { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java index 5f74edd700c48..e14cfdfebd3ed 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java @@ -76,6 +76,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * method handles. A relinkable call site will be managed by a * {@link DynamicLinker} object after being associated with it using its * {@link DynamicLinker#link(RelinkableCallSite)} method. + * @since 9 */ public interface RelinkableCallSite { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java b/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java index 73ee39b9002c5..5ec1f2737fbdb 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java @@ -32,6 +32,7 @@ /** * Provides security-checked access to a {@code MethodHandles.Lookup} object. * See {@link #getLookup()} for details. + * @since 9 */ public class SecureLookupSupplier { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java index 55b9acee7032e..b4c33250d38dd 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java @@ -62,6 +62,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * An enumeration of standard namespaces defined by Dynalink. + * @since 9 */ public enum StandardNamespace implements Namespace { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java index e58bf4e78bf0a..176a87acd3621 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java @@ -67,6 +67,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * disappears from their type signature. * {@link NamedOperation} can also be used to decorate {@link #CALL} and {@link #NEW} operations with a * diagnostic name, and as such it does not affect their type signature. + * @since 9 */ public enum StandardOperation implements Operation { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java index 386f386216ca8..ca09923292a77 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java @@ -135,6 +135,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * property and method names on classes and class instances, as well as access * to per-class linkers using the {@link #getLinkerForClass(Class)} * method.

+ * @since 9 */ public class BeansLinker implements GuardingDynamicLinker { private static final ClassValue linkers = new ClassValue<>() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java index 1fe50b916d9a1..c1e2f7eb71d15 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java @@ -67,6 +67,7 @@ * exception itself, as the linkage for the missing member is often conditional. * * @see BeansLinker#BeansLinker(MissingMemberHandlerFactory) + * @since 9 */ @FunctionalInterface public interface MissingMemberHandlerFactory { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java index 62bb74cb29ea7..ebd6c7e55e2fb 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java @@ -102,6 +102,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * constructor. You might want to expose a mechanism in your language for * selecting a constructor with an explicit signature through * {@link BeansLinker#getConstructorMethod(Class, String)}. + * @since 9 */ public final class StaticClass implements Serializable { private static final ClassValue staticClasses = new ClassValue<>() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java index 6c0dd438bbb2a..267752b0a238d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java @@ -70,10 +70,12 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * specific method with unrelated signatures. In these cases, language runtimes * can be asked to resolve the ambiguity by expressing preferences for one * conversion over the other. + * @since 9 */ public interface ConversionComparator { /** * Enumeration of possible outcomes of comparing one conversion to another. + * @since 9 */ enum Comparison { /** The conversions cannot be compared. **/ diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java index 1a1e23981c54a..174e63bff26ca 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java @@ -86,6 +86,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * throw an exception of the designated type. The guard, the switch points, and * the exception type are all optional (a guarded invocation having none of them * is unconditionally valid). + * @since 9 */ public class GuardedInvocation { private final MethodHandle invocation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java index 6c7750223620f..fa4f0cd454593 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java @@ -67,6 +67,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * another one. Typical usage is for implementing * {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer) * pre-link transformers}. + * @since 9 */ @FunctionalInterface public interface GuardedInvocationTransformer { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java index c604712ae43cf..e94cb7b912833 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java @@ -87,6 +87,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Languages can export linkers to other language runtimes for * {@link DynamicLinkerFactory#setClassLoader(ClassLoader) automatic discovery} * using a {@link GuardingDynamicLinkerExporter}. + * @since 9 */ public interface GuardingDynamicLinker { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java index 03be07cf45914..cd670a8fdbead 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java @@ -45,6 +45,7 @@ * security manager is present, to ensure that only trusted runtimes can * automatically export their linkers into other runtimes. * @see DynamicLinkerFactory#setClassLoader(ClassLoader) + * @since 9 */ public abstract class GuardingDynamicLinkerExporter implements Supplier> { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java index 981a39059af5c..bbd327d5bbefd 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java @@ -75,6 +75,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * these conversions, will cause more ambiguity for {@link BeansLinker} in * selecting the correct overload when trying to link to an overloaded Java * method. + * @since 9 */ public interface GuardingTypeConverterFactory { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java index 209c1920a3f8b..1feeed03d1560 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java @@ -69,6 +69,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * site. Instances of these requests will be constructed and passed to all * {@link GuardingDynamicLinker} objects managed by the {@link DynamicLinker} * that is trying to link the call site. + * @since 9 */ public interface LinkRequest { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java index e66babebf33f5..5a028205676d1 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java @@ -73,6 +73,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Interface for services provided to {@link GuardingDynamicLinker} instances by * the {@link DynamicLinker} that owns them. + * @since 9 */ public interface LinkerServices { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java index 2af6294c51740..e9ccd30ffed8d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java @@ -68,6 +68,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Typical usage is for implementing * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer) * internal objects filters}. + * @since 9 */ @FunctionalInterface public interface MethodHandleTransformer { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java index b830e375c12c2..394f81858ff35 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java @@ -70,6 +70,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * of * {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy) * method invocation conversions}. + * @since 9 */ @FunctionalInterface public interface MethodTypeConversionStrategy { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java index 53c1a66e86294..1565cfee552bd 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java @@ -68,6 +68,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers, * see {@link CompositeTypeBasedGuardingDynamicLinker}. + * @since 9 */ public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java index 8ae1f4754cf4e..c226a9c0b178c 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * A {@link GuardingDynamicLinker} that delegates sequentially to a list of * other guarding dynamic linkers in its * {@link #getGuardedInvocation(LinkRequest, LinkerServices)}. + * @since 9 */ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java index 184cc8e0ab801..a0805ff57d651 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java @@ -77,6 +77,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * returning true are then bound to the class, and next time a receiver of same * type is encountered, the linking is delegated to those linkers only, speeding * up dispatch. + * @since 9 */ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker { // Using a separate static class instance so there's no strong reference from the class value back to the composite diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java index 9929eeb7e5009..7a43f7ebbc0d7 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java @@ -80,6 +80,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * the parameter filter as being a wrapping method for exposing internal runtime * objects wrapped into an adapter with some public interface, and the return * value filter as being its inverse unwrapping method. + * @since 9 */ public class DefaultInternalObjectFilter implements MethodHandleTransformer { private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic( diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java index 9a456df5ebeab..7b0fd0e156b7c 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Utility methods for creating typical guards for * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)} * and for adjusting their method types. + * @since 9 */ public final class Guards { private static final Logger LOG = Logger diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java index ecf66e7d458a6..25792f0108b32 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * checked exceptions. It is useful in those cases when you're looking up * methods within your own codebase (therefore it is an error if they are not * present). + * @since 9 */ public final class Lookup { private final MethodHandles.Lookup lookup; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java index d8cfd8a9d9c2c..7a00b9fe3ea6d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java @@ -66,6 +66,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Default simple implementation of {@link LinkRequest}. + * @since 9 */ public class SimpleLinkRequest implements LinkRequest { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java index f5ee9e0909360..2a3d667d49a86 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java @@ -70,6 +70,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Various static utility methods for working with Java types. + * @since 9 */ public final class TypeUtilities { private TypeUtilities() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java index 03c7b9603f6b4..1218885ae9afd 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java @@ -60,5 +60,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Contains interfaces and classes that are used to link an {@code invokedynamic} call site. + * @since 9 */ package jdk.dynalink; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java index dbcf3ffd02153..84ecfa1db3887 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java @@ -75,6 +75,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@link #relink(GuardedInvocation, MethodHandle)} and * {@link #resetAndRelink(GuardedInvocation, MethodHandle)} * methods. + * @since 9 */ public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite { private final CallSiteDescriptor descriptor; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java index a026512242ab9..2f75b53fc3d93 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java @@ -84,6 +84,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Race conditions in linking are resolved by throwing away the * {@link GuardedInvocation} produced on the losing thread without incorporating * it into the chain, so it can lead to repeated linking for the same arguments. + * @since 9 */ public class ChainedCallSite extends AbstractRelinkableCallSite { private static final MethodHandle PRUNE_CATCHES; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java index 06f50b4ff8079..022d6088d01f8 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java @@ -71,6 +71,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * If the guard of that single invocation fails, or it has an invalidated * switch point, or its invalidating exception triggered, then the call site * will throw it away and ask its associated {@link DynamicLinker} to relink it. + * @since 9 */ public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite { /** From 07fce8eff207eedcbab29b52660f19333df7c574 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 9 Jan 2024 06:11:44 +0000 Subject: [PATCH 026/153] 8320864: Serial: Extract out Full GC related fields from ContiguousSpace Reviewed-by: kbarrett, sjohanss --- src/hotspot/share/gc/serial/genMarkSweep.cpp | 452 ++++++++++++++---- src/hotspot/share/gc/serial/genMarkSweep.hpp | 9 +- src/hotspot/share/gc/serial/generation.cpp | 31 -- src/hotspot/share/gc/serial/generation.hpp | 9 +- .../share/gc/serial/tenuredGeneration.hpp | 4 +- .../share/gc/shared/genCollectedHeap.cpp | 13 - .../share/gc/shared/genCollectedHeap.hpp | 12 - src/hotspot/share/gc/shared/space.cpp | 239 +-------- src/hotspot/share/gc/shared/space.hpp | 87 +--- src/hotspot/share/gc/shared/space.inline.hpp | 91 +--- src/hotspot/share/gc/shared/vmStructs_gc.hpp | 4 - 11 files changed, 363 insertions(+), 588 deletions(-) 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..30f1429fd40f2 100644 --- a/src/hotspot/share/gc/serial/generation.cpp +++ b/src/hotspot/share/gc/serial/generation.cpp @@ -218,34 +218,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..d93c2b66df717 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -51,7 +51,7 @@ class DefNewGeneration; class GCMemoryManager; class ContiguousSpace; -class CompactPoint; + class OopClosure; class GCStats; @@ -286,13 +286,6 @@ class Generation: public CHeapObj { GCStats* gc_stats() const { return _gc_stats; } virtual void update_gc_stats(Generation* current_generation, bool full) {} - // Mark sweep support phase2 - virtual void prepare_for_compaction(CompactPoint* cp); - // Mark sweep support phase3 - virtual void adjust_pointers(); - // Mark sweep support phase4 - virtual void compact(); - // Accessing "marks". // This function gives a generation a chance to note a point between diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 75e8bf8486051..6b2a5891c64cd 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -70,8 +70,6 @@ class TenuredGeneration: public Generation { GenerationCounters* _gen_counters; CSpaceCounters* _space_counters; - // Accessing spaces - TenuredSpace* space() const { return _the_space; } // Attempt to expand the generation by "bytes". Expand by at a // minimum "expand_bytes". Return true if some amount (not @@ -85,6 +83,8 @@ class TenuredGeneration: public Generation { public: virtual void compute_new_size(); + TenuredSpace* space() const { return _the_space; } + // Grow generation with specified size (returns false if unable to grow) bool grow_by(size_t bytes); // Grow generation to reserved size. diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index f4c21cce6dcda..cf101caae38b3 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -713,10 +713,6 @@ void GenCollectedHeap::process_roots(ScanningOption so, DEBUG_ONLY(ScavengableNMethods::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); } -void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) { - WeakProcessor::oops_do(root_closure); -} - bool GenCollectedHeap::no_allocs_since_save_marks() { return _young_gen->no_allocs_since_save_marks() && _old_gen->no_allocs_since_save_marks(); @@ -911,15 +907,6 @@ GenCollectedHeap* GenCollectedHeap::heap() { return named_heap(CollectedHeap::Serial); } -#if INCLUDE_SERIALGC -void GenCollectedHeap::prepare_for_compaction() { - // Start by compacting into same gen. - CompactPoint cp(_old_gen); - _old_gen->prepare_for_compaction(&cp); - _young_gen->prepare_for_compaction(&cp); -} -#endif // INCLUDE_SERIALGC - void GenCollectedHeap::verify(VerifyOption option /* ignored */) { log_debug(gc, verify)("%s", _old_gen->name()); _old_gen->verify(); diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp index 72548f6e2f54a..1c1759f1422be 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp @@ -292,11 +292,6 @@ class GenCollectedHeap : public CollectedHeap { CLDClosure* weak_cld_closure, CodeBlobToOopClosure* code_roots); - // Apply "root_closure" to all the weak roots of the system. - // These include JNI weak roots, string table, - // and referents of reachable weak refs. - void gen_process_weak_roots(OopClosure* root_closure); - // Set the saved marks of generations, if that makes sense. // In particular, if any generation might iterate over the oops // in other generations, it should call this method. @@ -340,13 +335,6 @@ class GenCollectedHeap : public CollectedHeap { HeapWord* mem_allocate_work(size_t size, bool is_tlab); -#if INCLUDE_SERIALGC - // For use by mark-sweep. As implemented, mark-sweep-compact is global - // in an essential way: compaction is performed across generations, by - // iterating over spaces. - void prepare_for_compaction(); -#endif - // Save the tops of the spaces in all generations void record_gen_tops_before_GC() PRODUCT_RETURN; diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 1c2afaa8b70ea..b6dc4e1e7d8f2 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -35,19 +35,13 @@ #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/java.hpp" -#include "runtime/prefetch.inline.hpp" #include "runtime/safepoint.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -#if INCLUDE_SERIALGC -#include "gc/serial/serialBlockOffsetTable.inline.hpp" -#include "gc/serial/defNewGeneration.hpp" -#endif ContiguousSpace::ContiguousSpace(): Space(), - _compaction_top(nullptr), _next_compaction_space(nullptr), _top(nullptr) { _mangler = new GenSpaceMangler(this); @@ -59,8 +53,7 @@ ContiguousSpace::~ContiguousSpace() { void ContiguousSpace::initialize(MemRegion mr, bool clear_space, - bool mangle_space) -{ + bool mangle_space) { HeapWord* bottom = mr.start(); HeapWord* end = mr.end(); assert(Universe::on_page_boundary(bottom) && Universe::on_page_boundary(end), @@ -70,7 +63,6 @@ void ContiguousSpace::initialize(MemRegion mr, if (clear_space) { clear(mangle_space); } - set_compaction_top(bottom); _next_compaction_space = nullptr; } @@ -80,7 +72,6 @@ void ContiguousSpace::clear(bool mangle_space) { if (ZapUnusedHeapArea && mangle_space) { mangle_unused_area(); } - _compaction_top = bottom(); } bool ContiguousSpace::is_free_block(const HeapWord* p) const { @@ -115,230 +106,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 +248,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..6b8279ec8bd05 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -184,29 +184,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 +198,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 +224,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 +238,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; } @@ -359,12 +287,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. @@ -419,8 +341,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/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index 696cdc00dc520..a5d671a3b9295 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -99,10 +99,6 @@ nonstatic_field(CollectedHeap, _is_gc_active, bool) \ nonstatic_field(CollectedHeap, _total_collections, unsigned int) \ \ - nonstatic_field(ContiguousSpace, _compaction_top, HeapWord*) \ - nonstatic_field(ContiguousSpace, _first_dead, HeapWord*) \ - nonstatic_field(ContiguousSpace, _end_of_live, HeapWord*) \ - \ nonstatic_field(ContiguousSpace, _top, HeapWord*) \ nonstatic_field(ContiguousSpace, _saved_mark_word, HeapWord*) \ \ From 7286f5291d6aad290fda778668eeb3a7cbfd8a55 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 9 Jan 2024 07:05:27 +0000 Subject: [PATCH 027/153] 8322829: Refactor nioBlocker to avoid blocking while holding Thread's interrupt lock Reviewed-by: jpai --- .../share/classes/java/lang/System.java | 4 +- .../share/classes/java/lang/Thread.java | 29 ++++++--- .../classes/java/lang/VirtualThread.java | 27 ++++++-- .../spi/AbstractInterruptibleChannel.java | 63 ++++++++++++------- .../nio/channels/spi/AbstractSelector.java | 28 +++++---- .../classes/sun/nio/ch/Interruptible.java | 21 ++++++- 6 files changed, 118 insertions(+), 54 deletions(-) diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 0c10079316722..227982af9eaf6 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 @@ -2374,7 +2374,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/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/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(); } From 4cf131a101d13699b1bf017895798c9bda87f551 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 9 Jan 2024 07:26:35 +0000 Subject: [PATCH 028/153] 8319716: RISC-V: Add SHA-2 Co-authored-by: Robbin Ehn Reviewed-by: fyang, mli, luhenry --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 77 +++- src/hotspot/cpu/riscv/globals_riscv.hpp | 2 + .../cpu/riscv/macroAssembler_riscv.hpp | 14 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 398 ++++++++++++++++++ src/hotspot/cpu/riscv/vm_version_riscv.cpp | 44 +- 5 files changed, 516 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 22554972583e3..ffe6dcf07ecd7 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1334,6 +1334,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 +1690,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 +1731,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 +1764,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 +1812,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 +1840,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. diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 60456c37ffe75..aa95cebec14cd 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -113,6 +113,8 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, UseZtso, false, EXPERIMENTAL, "Assume Ztso memory model") \ product(bool, UseZihintpause, false, EXPERIMENTAL, \ "Use Zihintpause instructions") \ + product(bool, UseZvkn, false, EXPERIMENTAL, \ + "Use Zvkn group extension, Zvkned, Zvknhb, Zvkb, Zvkt") \ product(bool, UseRVVForBigIntegerShiftIntrinsics, true, \ "Use RVV instructions for left/right shift of BigInteger") diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 3e0206746242c..4724dd85e7801 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1361,6 +1361,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 +1386,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/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..9a72b8d75a136 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -146,26 +146,11 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } - if (UseSHA) { - warning("SHA instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseSHA, false); - } - if (UseSHA1Intrinsics) { warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); } - if (UseSHA256Intrinsics) { - warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); - } - - if (UseSHA512Intrinsics) { - warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); - } - if (UseSHA3Intrinsics) { warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); @@ -272,6 +257,10 @@ void VM_Version::initialize() { // NOTE: Make sure codes dependent on UseRVV are put after c2_initialize(), // as there are extra checks inside it which could disable UseRVV // in some situations. + if (UseZvkn && !UseRVV) { + FLAG_SET_DEFAULT(UseZvkn, false); + warning("Cannot enable Zvkn on cpu without RVV support."); + } if (UseRVV) { if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { @@ -283,6 +272,31 @@ void VM_Version::initialize() { } FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } + + if (!UseZvkn && UseSHA) { + warning("SHA instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseSHA, false); + } else if (UseZvkn && FLAG_IS_DEFAULT(UseSHA)) { + FLAG_SET_DEFAULT(UseSHA, true); + } + + if (!UseSHA) { + if (UseSHA256Intrinsics) { + warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU, UseZvkn needed."); + FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); + } + if (UseSHA512Intrinsics) { + warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU, UseZvkn needed."); + FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); + } + } else { + if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { + FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); + } + if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { + FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); + } + } } #ifdef COMPILER2 From 30f93a29c2f677d0279176b89edf2ecdc06b42ca Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Tue, 9 Jan 2024 07:34:50 +0000 Subject: [PATCH 029/153] 8320069: RISC-V: Add Zcb instructions Reviewed-by: fyang, vkempik --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 259 +++++++++++++++++- .../cpu/riscv/macroAssembler_riscv.cpp | 71 +++-- .../cpu/riscv/macroAssembler_riscv.hpp | 19 +- src/hotspot/cpu/riscv/vm_version_riscv.hpp | 6 + .../linux_riscv/vm_version_linux_riscv.cpp | 2 + 5 files changed, 316 insertions(+), 41 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index ffe6dcf07ecd7..55c3e755c48eb 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -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); @@ -1938,9 +1938,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); @@ -2652,6 +2652,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 // -------------------------- @@ -2986,6 +2995,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/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 50ad3efbdb450..5008a0c08c219 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -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, diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 4724dd85e7801..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 diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 290b44eb0efe9..1ea853284ff15 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -110,6 +110,9 @@ class VM_Version : public Abstract_VM_Version { // Zic64b Cache blocks must be 64 bytes in size, naturally aligned in the address space. // Zihintpause Pause instruction HINT // + // Zc Code Size Reduction - Additional compressed instructions. + // Zcb Simple code-size saving instructions + // // Other features and settings // mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2.. // marchid Id for microarch. Mvendorid plus marchid uniquely identify the microarch. @@ -117,6 +120,8 @@ class VM_Version : public Abstract_VM_Version { // unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast) // satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64 + public: + #define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord // declaration name , extension name, bit pos ,in str, mapped flag) @@ -137,6 +142,7 @@ class VM_Version : public Abstract_VM_Version { decl(ext_Zbb , "Zbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \ decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \ + decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \ 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..354dbd70bb4e1 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -240,6 +240,8 @@ void VM_Version::rivos_features() { ext_Zbb.enable_feature(); ext_Zbs.enable_feature(); + ext_Zcb.enable_feature(); + ext_Zicsr.enable_feature(); ext_Zifencei.enable_feature(); ext_Zic64b.enable_feature(); From 075fed91bd144d94328e198b41ea2946961940e9 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 9 Jan 2024 08:19:57 +0000 Subject: [PATCH 030/153] 8323241: jcmd manpage should use lists for argument lists Reviewed-by: alanb --- src/jdk.jcmd/share/man/jcmd.1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index f0e14a9dbd2e5..0da1ee6912777 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -172,11 +172,11 @@ Impact: Low: Depends on code heap size and content. Holds CodeCache_lock during analysis step, usually sub-second duration. .PP \f[I]arguments\f[R]: -.PP +.IP \[bu] 2 \f[I]function\f[R]: (Optional) Function to be performed (aggregate, UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, discard (STRING, all) -.PP +.IP \[bu] 2 \f[I]granularity\f[R]: (Optional) Detail level - smaller value -> more detail (INT, 4096) .RE @@ -202,7 +202,7 @@ Adds compiler directives from a file. Impact: Low .PP \f[I]arguments\f[R]: -.PP +.IP \[bu] 2 \f[I]filename\f[R]: The name of the directives file (STRING, no default value) .RE @@ -253,7 +253,7 @@ Write map file for Linux perf tool. Impact: Low .PP \f[I]arguments\f[R]: -.PP +.IP \[bu] 2 \f[I]filename\f[R]: (Optional) The name of the map file (STRING, no default value) .RE From 52a6c37558fa970f595067bc1bb5bc2b710c3876 Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Tue, 9 Jan 2024 10:33:52 +0000 Subject: [PATCH 031/153] 8322858: compiler/c2/aarch64/TestFarJump.java fails on AArch64 due to unexpected PrintAssembly output Reviewed-by: aph, thartmann --- test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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); From 6e9671a8a87a369c6986854a2c3c32cc9d7027ba Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 9 Jan 2024 10:37:02 +0000 Subject: [PATCH 032/153] 8323264: Serial: Remove unused GenerationBlockSizeClosure Reviewed-by: stefank --- src/hotspot/share/gc/serial/generation.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/hotspot/share/gc/serial/generation.cpp b/src/hotspot/share/gc/serial/generation.cpp index 30f1429fd40f2..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; From 7d42aa15137814761ff314112a055e835a659cf1 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Tue, 9 Jan 2024 11:31:50 +0000 Subject: [PATCH 033/153] 8310277: jdk/javadoc/doclet/testMethodCommentAlgorithm/TestMethodCommentsAlgorithm.java fails with IllegalStateException Reviewed-by: jjg --- .../TestMethodCommentsAlgorithm.java | 155 +++++++++--------- 1 file changed, 77 insertions(+), 78 deletions(-) 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()); From 37a61720b60a503a958b35c422ca4f2eb06d62fb Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Tue, 9 Jan 2024 11:36:36 +0000 Subject: [PATCH 034/153] 8322936: Update blessed-modifier-order.sh for default, sealed, and non-sealed Reviewed-by: erikj, rriggs, martin --- bin/blessed-modifier-order.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) 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" From ff499ef79f6bffe95afa17a9aa312ac9f67fba18 Mon Sep 17 00:00:00 2001 From: Lei Zaakjyu Date: Tue, 9 Jan 2024 13:26:38 +0000 Subject: [PATCH 035/153] 8233443: G1 DetailedUsage class names overly generic for global namespace Reviewed-by: ayang, gli, tschatzl --- src/hotspot/share/gc/g1/g1HeapTransition.cpp | 4 ++-- src/hotspot/share/gc/g1/g1HeapTransition.hpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) 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; From 52c7ff1d81940d6d0d1e3dd7ad0447c80708161c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 9 Jan 2024 13:47:32 +0000 Subject: [PATCH 036/153] 8322330: JavadocHelperTest.java OOMEs with Parallel GC and ZGC Reviewed-by: ayang, aboldtch --- .../jdk/internal/shellsupport/doc/JavadocHelperTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From 438ab7c115249d7501edfbb2d3c62e96ae824181 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 9 Jan 2024 14:23:42 +0000 Subject: [PATCH 037/153] 8323284: Remove unused FilteringClosure declaration Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/shared/space.hpp | 1 - src/hotspot/share/oops/oop.hpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 6b8279ec8bd05..541747e38f838 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. 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; From 886386c0396d4cd4f1be24906a77c9dbfc8626e6 Mon Sep 17 00:00:00 2001 From: Lei Zaakjyu Date: Tue, 9 Jan 2024 15:52:39 +0000 Subject: [PATCH 038/153] 8322890: Directly return in OldPLABSizeConstraintFunc Reviewed-by: ayang, tschatzl --- src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) 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) { From ee98d262181f5822609674c71c85ad4576ac1632 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 9 Jan 2024 17:03:28 +0000 Subject: [PATCH 039/153] 8323066: gc/g1/TestSkipRebuildRemsetPhase.java fails with 'Skipping Remembered Set Rebuild.' missing Reviewed-by: ayang, iwalulya --- test/hotspot/jtreg/ProblemList.txt | 1 - .../gc/g1/TestSkipRebuildRemsetPhase.java | 24 ++++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d82f4a919fa81..754cf68ba591f 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -93,7 +93,6 @@ 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 ############################################################################# 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; - } } } + From dd8ae616437398f957f9b4f09cf2c7f1d0bd0938 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Tue, 9 Jan 2024 19:31:03 +0000 Subject: [PATCH 040/153] 8322237: Heap dump contains duplicate thread records for mounted virtual threads Reviewed-by: dholmes, sspitsyn --- src/hotspot/share/services/heapDumper.cpp | 18 +++++++++++++++++- .../vthread/HeapDump/VThreadInHeapDump.java | 19 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) 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/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); From bc05893f820ff8158897f84b9d2fdaed2cd1661b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 9 Jan 2024 19:37:28 +0000 Subject: [PATCH 041/153] 8323318: Remove unused Space::is_free_block Reviewed-by: tschatzl --- src/hotspot/share/gc/shared/space.cpp | 4 ---- src/hotspot/share/gc/shared/space.hpp | 5 ----- 2 files changed, 9 deletions(-) diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index b6dc4e1e7d8f2..67d3ad5338388 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -74,10 +74,6 @@ void ContiguousSpace::clear(bool mangle_space) { } } -bool ContiguousSpace::is_free_block(const HeapWord* p) const { - return p >= _top; -} - #ifndef PRODUCT void ContiguousSpace::set_top_for_allocations(HeapWord* v) { diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 541747e38f838..8299a7e628913 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -133,9 +133,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)); @@ -273,8 +270,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()); } From f3be138eb80c9e7f6cc21afb75cda9e49b667c8a Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 9 Jan 2024 22:04:02 +0000 Subject: [PATCH 042/153] 8322809: SystemModulesMap::classNames and moduleNames arrays do not match the order Reviewed-by: alanb --- .../internal/plugins/SystemModulesPlugin.java | 13 +- .../ModuleMainClassTest.java | 145 ++++++++++++++++++ .../src/com.foo/com/foo/Main.java | 53 +++++++ .../src/com.foo/module-info.java | 27 ++++ .../src/net.foo/module-info.java | 26 ++++ .../src/net.foo/net/foo/Main.java | 54 +++++++ 6 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java create mode 100644 test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java create mode 100644 test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java create mode 100644 test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java create mode 100644 test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 735c969a88603..40693b33d6db2 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.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 @@ -1827,6 +1827,9 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, // write the class file to the pool as a resource String rn = "/java.base/" + SYSTEM_MODULES_MAP_CLASSNAME + ".class"; + // sort the map of module name to the class name of the generated SystemModules class + List> systemModulesMap = map.entrySet() + .stream().sorted(Map.Entry.comparingByKey()).toList(); ResourcePoolEntry e = ResourcePoolEntry.create(rn, ClassFile.of().build( CD_SYSTEM_MODULES_MAP, clb -> clb.withFlags(ACC_FINAL + ACC_SUPER) @@ -1877,10 +1880,10 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, cob.anewarray(CD_String); int index = 0; - for (String moduleName : sorted(map.keySet())) { + for (Map.Entry entry : systemModulesMap) { cob.dup() // arrayref .constantInstruction(index) - .constantInstruction(moduleName) + .constantInstruction(entry.getKey()) .aastore(); index++; } @@ -1898,10 +1901,10 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, .anewarray(CD_String); int index = 0; - for (String className : sorted(map.values())) { + for (Map.Entry entry : systemModulesMap) { cob.dup() // arrayref .constantInstruction(index) - .constantInstruction(className.replace('/', '.')) + .constantInstruction(entry.getValue().replace('/', '.')) .aastore(); index++; } 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/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java new file mode 100644 index 0000000000000..99107602506c7 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module com.foo { + requires jdk.httpserver; + requires net.foo; +} diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java new file mode 100644 index 0000000000000..360a989d9b339 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +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); + } + } + +} From aba19334eaeb46d37169cddeef929b13e050a60e Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 9 Jan 2024 22:05:37 +0000 Subject: [PATCH 043/153] 8323210: Update the usage of cmsFLAGS_COPY_ALPHA Reviewed-by: prr --- src/java.desktop/share/native/liblcms/LCMS.c | 9 +++++++-- .../cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) 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/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 { From e9f7db304559cbc8e2b46ea30496d3c570569f4c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Jan 2024 22:26:17 +0000 Subject: [PATCH 044/153] 8322880: Eliminate -Wparentheses warnings in arm32 code Reviewed-by: shade, dholmes --- src/hotspot/cpu/arm/arm.ad | 4 ++-- src/hotspot/cpu/arm/assembler_arm.hpp | 4 ++-- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 6 +++--- src/hotspot/cpu/arm/frame_arm.inline.hpp | 4 ++-- src/hotspot/cpu/arm/nativeInst_arm_32.cpp | 4 ++-- src/hotspot/cpu/arm/nativeInst_arm_32.hpp | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) 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.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 9191d03baf0ec..43cc523658b5a 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; } diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp index e5e5e89c2002b..429a0c000f637 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(); diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp index 804292c24b086..a7a51f017d22d 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; } From 28d8149c693a9470bbde4b1a27c4b9be6c5f365c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Jan 2024 22:33:13 +0000 Subject: [PATCH 045/153] 8323115: x86-32: Incorrect predicates for cmov instruct transforms with UseSSE Reviewed-by: shade, thartmann --- src/hotspot/cpu/x86/x86_32.ad | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) 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 %{ From a5071e010be8c79f1a3cd96f7325d04bac8f7ae0 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Jan 2024 22:47:36 +0000 Subject: [PATCH 046/153] 8322817: RISC-V: Eliminate -Wparentheses warnings in riscv code Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/frame_riscv.inline.hpp | 4 ++-- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp index dfec388019216..37f273be6c19b 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; } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 5008a0c08c219..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. @@ -4904,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()))); @@ -4948,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()))); From 376051a9be95e0e4acf3c59d0eba3e9ef8727d79 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 9 Jan 2024 23:11:21 +0000 Subject: [PATCH 047/153] 8320919: Clarify Locale related system properties Reviewed-by: smarks, rriggs --- .../share/classes/java/util/Locale.java | 91 +++++++++++++++++-- 1 file changed, 81 insertions(+), 10 deletions(-) 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 From f4ca41ad75fa78a08ff069ba0b6ac3596e35c23d Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 10 Jan 2024 00:19:05 +0000 Subject: [PATCH 048/153] 8322816: RISC-V: Incorrect guarantee in patch_vtype Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 55c3e755c48eb..f44840d9f8cc7 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. @@ -1156,10 +1156,8 @@ static Assembler::SEW elemtype_to_sew(BasicType etype) { } #define patch_vtype(hsb, lsb, vlmul, vsew, vta, vma, vill) \ - if (vill == 1) { \ - guarantee((vlmul | vsew | vta | vma == 0), \ - "the other bits in vtype shall be zero"); \ - } \ + /* If vill then other bits of vtype must be zero. */ \ + guarantee(!vill, "vill not supported"); \ patch((address)&insn, lsb + 2, lsb, vlmul); \ patch((address)&insn, lsb + 5, lsb + 3, vsew); \ patch((address)&insn, lsb + 6, vta); \ From 856922747358291ed2e112c328fb776a7be2567d Mon Sep 17 00:00:00 2001 From: Zhiqiang Zang Date: Wed, 10 Jan 2024 07:31:56 +0000 Subject: [PATCH 049/153] 8322589: Add Ideal transformation: (~a) & (~b) => ~(a | b) Reviewed-by: thartmann, epeter --- src/hotspot/share/opto/addnode.cpp | 18 ++++- src/hotspot/share/opto/addnode.hpp | 9 ++- src/hotspot/share/opto/mulnode.cpp | 16 ++++- .../c2/irTests/AndINodeIdealizationTests.java | 25 +++++-- .../c2/irTests/AndLNodeIdealizationTests.java | 68 +++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 7 +- 6 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 305501bfb1467..49d17d84fc91c 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,6 +253,22 @@ AddNode* AddNode::make(Node* in1, Node* in2, BasicType bt) { return nullptr; } +bool AddNode::is_not(PhaseGVN* phase, Node* n, BasicType bt) { + return n->Opcode() == Op_Xor(bt) && phase->type(n->in(2)) == TypeInteger::minus_1(bt); +} + +AddNode* AddNode::make_not(PhaseGVN* phase, Node* n, BasicType bt) { + switch (bt) { + case T_INT: + return new XorINode(n, phase->intcon(-1)); + case T_LONG: + return new XorLNode(n, phase->longcon(-1L)); + default: + fatal("Not implemented for %s", type2name(bt)); + } + return nullptr; +} + //============================================================================= //------------------------------Idealize--------------------------------------- Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) { diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 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/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/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/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)"); From 88378ed0584c7eb0849b6fc1e361fd8ea0698caf Mon Sep 17 00:00:00 2001 From: Tobias Holenstein Date: Wed, 10 Jan 2024 08:30:47 +0000 Subject: [PATCH 050/153] 8277869: Maven POMs are using HTTP links where HTTPS is available Reviewed-by: kvn, thartmann --- src/utils/IdealGraphVisualizer/Bytecodes/pom.xml | 2 +- .../igv/bytecodes/BytecodeViewTopComponentSettings.xml | 2 +- .../igv/bytecodes/BytecodeViewTopComponentWstcref.xml | 2 +- .../main/resources/com/sun/hotspot/igv/bytecodes/layer.xml | 2 +- src/utils/IdealGraphVisualizer/ControlFlow/pom.xml | 2 +- .../igv/controlflow/ControlFlowTopComponentSettings.xml | 2 +- .../igv/controlflow/ControlFlowTopComponentWstcref.xml | 2 +- .../resources/com/sun/hotspot/igv/controlflow/layer.xml | 2 +- src/utils/IdealGraphVisualizer/Coordinator/pom.xml | 2 +- .../hotspot/igv/coordinator/OutlineTopComponentSettings.xml | 2 +- .../hotspot/igv/coordinator/OutlineTopComponentWstcref.xml | 2 +- .../sun/hotspot/igv/coordinator/StandardConfiguration.xml | 2 +- .../resources/com/sun/hotspot/igv/coordinator/layer.xml | 2 +- src/utils/IdealGraphVisualizer/Data/pom.xml | 2 +- .../sun/hotspot/igv/data/serialization/graphdocument.xsd | 2 +- src/utils/IdealGraphVisualizer/Difference/pom.xml | 2 +- src/utils/IdealGraphVisualizer/Filter/pom.xml | 2 +- .../src/main/resources/com/sun/hotspot/igv/filter/layer.xml | 2 +- src/utils/IdealGraphVisualizer/FilterWindow/pom.xml | 2 +- .../hotspot/igv/filterwindow/FilterTopComponentSettings.xml | 2 +- .../hotspot/igv/filterwindow/FilterTopComponentWstcref.xml | 2 +- .../resources/com/sun/hotspot/igv/filterwindow/layer.xml | 2 +- src/utils/IdealGraphVisualizer/Graph/pom.xml | 2 +- src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml | 2 +- src/utils/IdealGraphVisualizer/Layout/pom.xml | 2 +- src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml | 2 +- src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml | 2 +- src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml | 2 +- .../resources/com/sun/hotspot/igv/servercompiler/layer.xml | 2 +- src/utils/IdealGraphVisualizer/Settings/pom.xml | 2 +- .../main/resources/com/sun/hotspot/igv/settings/layer.xml | 2 +- src/utils/IdealGraphVisualizer/Util/pom.xml | 2 +- src/utils/IdealGraphVisualizer/View/pom.xml | 2 +- .../src/main/resources/com/sun/hotspot/igv/view/layer.xml | 2 +- .../resources/com/sun/hotspot/igv/view/propertiesWsmode.xml | 2 +- .../com/sun/hotspot/igv/view/propertiesWstcref.xml | 2 +- src/utils/IdealGraphVisualizer/application/pom.xml | 2 +- src/utils/IdealGraphVisualizer/branding/pom.xml | 2 +- src/utils/IdealGraphVisualizer/pom.xml | 2 +- src/utils/LogCompilation/pom.xml | 6 +++--- 40 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml b/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml index e87ad7fb50998..0a4f81d4d4ad9 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml +++ b/src/utils/IdealGraphVisualizer/Bytecodes/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/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 From 40861761c2b0bb5ae548afc4752dc7cee3bf506a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 10 Jan 2024 09:57:16 +0000 Subject: [PATCH 051/153] 8322987: Remove gc/stress/gclocker/TestGCLocker* since they always fail with OOME Reviewed-by: ayang, lmesnik --- test/hotspot/jtreg/ProblemList.txt | 3 - .../gc/stress/gclocker/TestGCLocker.java | 228 ------------------ .../stress/gclocker/TestGCLockerWithG1.java | 39 --- .../gclocker/TestGCLockerWithParallel.java | 39 --- .../gclocker/TestGCLockerWithSerial.java | 40 --- .../gclocker/TestGCLockerWithShenandoah.java | 64 ----- .../gc/stress/gclocker/libTestGCLocker.c | 35 --- 7 files changed, 448 deletions(-) delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 754cf68ba591f..4cb1ec5489880 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -89,9 +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 ############################################################################# 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/TestGCLockerWithG1.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java deleted file mode 100644 index a70a35daa63ea..0000000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, 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. - * - */ - -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 - */ -public class TestGCLockerWithG1 { - public static void main(String[] args) { - String[] testArgs = {"2", "G1 Old Gen"}; - TestGCLocker.main(testArgs); - } -} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java deleted file mode 100644 index eeee969a2521a..0000000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, 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. - * - */ - -package gc.stress.gclocker; - -/* - * @test TestGCLockerWithParallel - * @library / - * @requires vm.gc.Parallel - * @summary Stress Parallel's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseParallelGC gc.stress.gclocker.TestGCLockerWithParallel - */ -public class TestGCLockerWithParallel { - public static void main(String[] args) { - String[] testArgs = {"2", "PS Old Gen"}; - TestGCLocker.main(testArgs); - } -} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java deleted file mode 100644 index 9de8fa88ca708..0000000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017, 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. - * - */ - -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 - */ -public class TestGCLockerWithSerial { - public static void main(String[] args) { - String[] testArgs = {"2", "Tenured Gen"}; - TestGCLocker.main(testArgs); - } -} 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/gc/stress/gclocker/libTestGCLocker.c b/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c deleted file mode 100644 index 2ac2064775c26..0000000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. - * 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 - -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); -} From 9847086466359e330fdb7dceb29c7d31cf0242ce Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Jan 2024 10:56:24 +0000 Subject: [PATCH 052/153] 8323499: Remove unused methods in space.hpp Reviewed-by: tschatzl --- src/hotspot/share/gc/shared/space.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 8299a7e628913..85f870ba1e2af 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -84,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; @@ -304,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; From 8d9479910f587a2524a2d4068174f14e224ff2cf Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Jan 2024 11:28:51 +0000 Subject: [PATCH 053/153] 8322828: Parallel: Rename ParallelCompactData::_region_start Reviewed-by: tschatzl, ehelin --- .../share/gc/parallel/psParallelCompact.cpp | 25 +++++----- .../share/gc/parallel/psParallelCompact.hpp | 49 +++++++++---------- 2 files changed, 36 insertions(+), 38 deletions(-) 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..173c883c498d4 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -399,7 +399,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; } @@ -481,13 +481,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; @@ -662,18 +661,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 +685,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* @@ -707,16 +706,16 @@ ParallelCompactData::region_to_addr(size_t region, size_t offset) const 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); } @@ -729,17 +728,17 @@ ParallelCompactData::is_region_aligned(HeapWord* addr) const inline size_t ParallelCompactData::block_offset(const 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 (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* @@ -752,7 +751,7 @@ inline HeapWord* ParallelCompactData::block_to_addr(size_t block) const { assert(block < _block_count, "block out of range"); - return _region_start + (block << Log2BlockSize); + return _heap_start + (block << Log2BlockSize); } inline size_t @@ -764,16 +763,16 @@ ParallelCompactData::region_to_block_idx(size_t region) const 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"); + assert(addr >= _heap_start, "bad addr"); + assert(addr <= _heap_end, "bad addr"); return block_align_down(addr + BlockSizeOffsetMask); } From 88dafe564f163ed738a8cb6adc449b94e606999f Mon Sep 17 00:00:00 2001 From: Guoxiong Li Date: Wed, 10 Jan 2024 12:15:38 +0000 Subject: [PATCH 054/153] 8314629: Generational ZGC: Clearing All SoftReferences log line lacks GCId Reviewed-by: eosterlund, tschatzl --- src/hotspot/share/gc/z/zReferenceProcessor.cpp | 8 +++++++- src/hotspot/share/gc/z/zReferenceProcessor.hpp | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) 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; From 2e472fe7ea98ca1f07a90d1ad6704e8b2bb3afcf Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Wed, 10 Jan 2024 12:18:01 +0000 Subject: [PATCH 055/153] 8322294: Cleanup NativePostCallNop Reviewed-by: mdoerr, aph --- src/hotspot/cpu/aarch64/frame_aarch64.hpp | 2 -- .../cpu/aarch64/frame_aarch64.inline.hpp | 14 ------------- .../cpu/aarch64/nativeInst_aarch64.cpp | 13 ++++++++---- .../cpu/aarch64/nativeInst_aarch64.hpp | 14 ++++++++----- src/hotspot/cpu/arm/frame_arm.hpp | 2 -- src/hotspot/cpu/arm/frame_arm.inline.hpp | 14 ------------- src/hotspot/cpu/arm/nativeInst_arm_32.cpp | 4 ---- src/hotspot/cpu/arm/nativeInst_arm_32.hpp | 4 ++-- src/hotspot/cpu/ppc/frame_ppc.hpp | 2 -- src/hotspot/cpu/ppc/frame_ppc.inline.hpp | 14 ------------- src/hotspot/cpu/ppc/nativeInst_ppc.cpp | 4 ---- src/hotspot/cpu/ppc/nativeInst_ppc.hpp | 4 ++-- src/hotspot/cpu/riscv/frame_riscv.hpp | 2 -- src/hotspot/cpu/riscv/frame_riscv.inline.hpp | 14 ------------- src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 21 ++++++++++++++----- src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 4 ++-- src/hotspot/cpu/s390/frame_s390.hpp | 1 - src/hotspot/cpu/s390/frame_s390.inline.hpp | 14 ------------- src/hotspot/cpu/s390/nativeInst_s390.hpp | 4 ++-- src/hotspot/cpu/x86/frame_x86.hpp | 2 -- src/hotspot/cpu/x86/frame_x86.inline.hpp | 14 ------------- src/hotspot/cpu/x86/nativeInst_x86.cpp | 11 +++++++--- src/hotspot/cpu/x86/nativeInst_x86.hpp | 12 +++++++++-- src/hotspot/cpu/zero/frame_zero.hpp | 2 -- src/hotspot/cpu/zero/frame_zero.inline.hpp | 5 ----- src/hotspot/cpu/zero/nativeInst_zero.hpp | 4 ++-- src/hotspot/share/code/codeCache.inline.hpp | 14 +++++++------ src/hotspot/share/code/nmethod.cpp | 5 +---- src/hotspot/share/runtime/frame.hpp | 2 ++ src/hotspot/share/runtime/frame.inline.hpp | 13 ++++++++++++ 30 files changed, 86 insertions(+), 149 deletions(-) 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 5c850c6bcbd65..d3ae7871f61f2 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -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..a12caa3daeefb 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -560,18 +560,23 @@ static bool is_movk_to_zr(uint32_t insn) { } #endif -void NativePostCallNop::patch(jint diff) { +bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { + if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) { + return false; // cannot encode + } + uint32_t data = ((uint32_t)oopmap_slot << 24) | cb_offset; #ifdef ASSERT - assert(diff != 0, "must be"); + assert(data != 0, "must be"); uint32_t insn1 = uint_at(4); uint32_t insn2 = uint_at(8); assert (is_movk_to_zr(insn1) && is_movk_to_zr(insn2), "must be"); #endif - uint32_t lo = diff & 0xffff; - uint32_t hi = (uint32_t)diff >> 16; + uint32_t lo = data & 0xffff; + uint32_t hi = data >> 16; Instruction_aarch64::patch(addr_at(4), 20, 5, lo); Instruction_aarch64::patch(addr_at(8), 20, 5, hi); + return true; // successfully encoded } void NativeDeoptInstruction::verify() { diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 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/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 43cc523658b5a..8a08c0d0e9c43 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -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 429a0c000f637..23ee01d335264 100644 --- a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp @@ -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 a7a51f017d22d..7006d7709813a 100644 --- a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp @@ -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 861c6adc491e4..220b9c3241e01 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -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/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/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 37f273be6c19b..33727a8c6d0a7 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -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/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/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/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/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/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/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/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; From 679f526d89f679b1f42a1a4acdecf93686bde8a4 Mon Sep 17 00:00:00 2001 From: Guoxiong Li Date: Wed, 10 Jan 2024 12:18:12 +0000 Subject: [PATCH 056/153] 8322278: Generational ZGC: Adjust the comment of ZHeuristics::use_per_cpu_shared_small_pages Reviewed-by: eosterlund --- src/hotspot/share/gc/z/zHeuristics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp index bcd9dd844052b..df2f5f68489cc 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; From b2a39c576706622b624314c89fa6d10d0b422f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 10 Jan 2024 13:03:36 +0000 Subject: [PATCH 057/153] 8316241: Test jdk/jdk/jfr/jvm/TestChunkIntegrity.java failed Reviewed-by: egahlin --- .../recorder/checkpoint/types/jfrTypeSet.cpp | 1037 +++++++++-------- .../checkpoint/types/jfrTypeSetUtils.cpp | 30 +- .../checkpoint/types/jfrTypeSetUtils.hpp | 47 +- .../traceid/jfrTraceIdLoadBarrier.inline.hpp | 41 +- .../storage/jfrMemorySpace.inline.hpp | 2 +- 5 files changed, 626 insertions(+), 531 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 94ac07729697e..2d49c5aa405fb 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -66,20 +66,38 @@ static bool _class_unload = false; static bool _flushpoint = false; static bool _initial_type_set = true; -static bool current_epoch() { - return _class_unload || _flushpoint; +static inline bool flushpoint() { + return _flushpoint; } -static bool previous_epoch() { +static inline bool unloading() { + return _class_unload; +} + +static inline bool current_epoch() { + return flushpoint() || unloading(); +} + +static inline bool previous_epoch() { return !current_epoch(); } -static bool is_initial_typeset_for_chunk() { - return _initial_type_set && !_class_unload; +template +static inline bool used(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return current_epoch() ? USED_THIS_EPOCH(ptr) : USED_PREVIOUS_EPOCH(ptr); +} + +template +static inline bool not_used(const T* ptr) { + return !used(ptr); } -static bool is_complete() { - return !_artifacts->has_klass_entries() && current_epoch(); +template +static void do_artifact(const T* ptr) { + if (used(ptr)) { + _subsystem_callback->do_artifact(ptr); + } } static traceid mark_symbol(KlassPtr klass, bool leakp) { @@ -94,66 +112,107 @@ static traceid get_bootstrap_name(bool leakp) { return _artifacts->bootstrap_name(leakp); } -static const char* primitive_name(KlassPtr type_array_klass) { - switch (type_array_klass->name()->base()[1]) { - case JVM_SIGNATURE_BOOLEAN: return "boolean"; - case JVM_SIGNATURE_BYTE: return "byte"; - case JVM_SIGNATURE_CHAR: return "char"; - case JVM_SIGNATURE_SHORT: return "short"; - case JVM_SIGNATURE_INT: return "int"; - case JVM_SIGNATURE_LONG: return "long"; - case JVM_SIGNATURE_FLOAT: return "float"; - case JVM_SIGNATURE_DOUBLE: return "double"; +template +static traceid artifact_id(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return JfrTraceId::load_raw(ptr); +} + +template +static traceid artifact_tag(const T* ptr, bool leakp) { + assert(ptr != nullptr, "invariant"); + if (leakp) { + if (IS_NOT_LEAKP(ptr)) { + SET_LEAKP(ptr); + } + assert(IS_LEAKP(ptr), "invariant"); + return artifact_id(ptr); } - assert(false, "invalid type array klass"); - return nullptr; + if (not_used(ptr)) { + SET_TRANSIENT(ptr); + } + assert(used(ptr), "invariant"); + return artifact_id(ptr); } -static Symbol* primitive_symbol(KlassPtr type_array_klass) { - if (type_array_klass == nullptr) { - // void.class - static Symbol* const void_class_name = SymbolTable::probe("void", 4); - assert(void_class_name != nullptr, "invariant"); - return void_class_name; +static inline bool should_do_cld_klass(const Klass* klass, bool leakp) { + return klass != nullptr && _artifacts->should_do_cld_klass(klass, leakp); +} + +static inline KlassPtr get_cld_klass(CldPtr cld, bool leakp) { + if (cld == nullptr) { + return nullptr; } - const char* const primitive_type_str = primitive_name(type_array_klass); - assert(primitive_type_str != nullptr, "invariant"); - Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, (int)strlen(primitive_type_str)); - assert(primitive_type_sym != nullptr, "invariant"); - return primitive_type_sym; + assert(leakp ? IS_LEAKP(cld) : used(cld), "invariant"); + KlassPtr cld_klass = cld->class_loader_klass(); + if (cld_klass == nullptr) { + return nullptr; + } + if (should_do_cld_klass(cld_klass, leakp)) { + if (current_epoch()) { + // This will enqueue the klass, which is important for + // reachability when doing clear and reset at rotation. + JfrTraceId::load(cld_klass); + } else { + artifact_tag(cld_klass, leakp); + } + return cld_klass; + } + return nullptr; } -template -static traceid artifact_id(const T* ptr) { - assert(ptr != nullptr, "invariant"); - return JfrTraceId::load_raw(ptr); +static inline CldPtr get_cld(ModPtr mod) { + return mod != nullptr ? mod->loader_data() : nullptr; } -static traceid package_id(KlassPtr klass, bool leakp) { +static ClassLoaderData* get_cld(const Klass* klass) { assert(klass != nullptr, "invariant"); - PkgPtr pkg_entry = klass->package(); - if (pkg_entry == nullptr) { - return 0; - } - if (leakp) { - SET_LEAKP(pkg_entry); + if (klass->is_objArray_klass()) { + klass = ObjArrayKlass::cast(klass)->bottom_klass(); } - // package implicitly tagged already - return artifact_id(pkg_entry); + return klass->is_non_strong_hidden() ? nullptr : klass->class_loader_data(); +} + +static inline ModPtr get_module(PkgPtr pkg) { + return pkg != nullptr ? pkg->module() : nullptr; +} + +static inline PkgPtr get_package(KlassPtr klass) { + return klass != nullptr ? klass->package() : nullptr; +} + +static inline KlassPtr get_module_cld_klass(KlassPtr klass, bool leakp) { + assert(klass != nullptr, "invariant"); + return get_cld_klass(get_cld(get_module(get_package(klass))), leakp); +} + +static traceid cld_id(CldPtr cld, bool leakp) { + assert(cld != nullptr, "invariant"); + return artifact_tag(cld, leakp); } static traceid module_id(PkgPtr pkg, bool leakp) { assert(pkg != nullptr, "invariant"); - ModPtr module_entry = pkg->module(); - if (module_entry == nullptr) { + ModPtr mod = get_module(pkg); + if (mod == nullptr) { return 0; } - if (leakp) { - SET_LEAKP(module_entry); - } else { - SET_TRANSIENT(module_entry); + CldPtr cld = get_cld(mod); + if (cld != nullptr) { + cld_id(cld, leakp); } - return artifact_id(module_entry); + return artifact_tag(mod, leakp); +} + +static traceid package_id(KlassPtr klass, bool leakp) { + assert(klass != nullptr, "invariant"); + PkgPtr pkg = get_package(klass); + if (pkg == nullptr) { + return 0; + } + // Ensure module and its CLD gets tagged. + module_id(pkg, leakp); + return artifact_tag(pkg, leakp); } static traceid method_id(KlassPtr klass, MethodPtr method) { @@ -162,16 +221,6 @@ static traceid method_id(KlassPtr klass, MethodPtr method) { return METHOD_ID(klass, method); } -static traceid cld_id(CldPtr cld, bool leakp) { - assert(cld != nullptr, "invariant"); - if (leakp) { - SET_LEAKP(cld); - } else { - SET_TRANSIENT(cld); - } - return artifact_id(cld); -} - template static s4 get_flags(const T* ptr) { assert(ptr != nullptr, "invariant"); @@ -183,73 +232,203 @@ static u4 get_primitive_flags() { return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC; } -static ClassLoaderData* get_cld(const Klass* klass) { - assert(klass != nullptr, "invariant"); - if (klass->is_objArray_klass()) { - klass = ObjArrayKlass::cast(klass)->bottom_klass(); +class PackageFieldSelector { + public: + typedef PkgPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + return klass->package(); } - if (klass->is_non_strong_hidden()) return nullptr; - return klass->class_loader_data(); -} +}; + +class ModuleFieldSelector { + public: + typedef ModPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + PkgPtr pkg = klass->package(); + return pkg != nullptr ? pkg->module() : nullptr; + } +}; + +class KlassCldFieldSelector { + public: + typedef CldPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + return get_cld(klass); + } +}; + +class ModuleCldFieldSelector { + public: + typedef CldPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + ModPtr mod = ModuleFieldSelector::select(klass); + return mod != nullptr ? mod->loader_data() : nullptr; + } +}; + +template +class SerializePredicate { + bool _class_unload; + public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(T const& value) { + assert(value != nullptr, "invariant"); + return _class_unload ? _artifacts->should_do_unloading_artifact(value) : IS_NOT_SERIALIZED(value); + } +}; + +template <> +class SerializePredicate { + bool _class_unload; +public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(const Klass* klass) { + assert(klass != nullptr, "invariant"); + return _class_unload ? true : IS_NOT_SERIALIZED(klass); + } +}; + +template <> +class SerializePredicate { + bool _class_unload; +public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(const Method* method) { + assert(method != nullptr, "invariant"); + return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method); + } +}; template static void set_serialized(const T* ptr) { assert(ptr != nullptr, "invariant"); - SET_SERIALIZED(ptr); - assert(IS_SERIALIZED(ptr), "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_CLEARED_BIT(ptr); } + SET_SERIALIZED(ptr); + assert(IS_SERIALIZED(ptr), "invariant"); } /* - * In C++03, functions used as template parameters must have external linkage; - * this restriction was removed in C++11. Change back to "static" and - * rename functions when C++11 becomes available. + *********************** Klasses ************************* + * + * When we process a Klass, we need to process its transitive closure. + * + * This includes two branches: + * + * [1] Klass -> CLD -> class_loader_Klass + * [2] Klass -> PackageEntry -> ModuleEntry -> CLD -> class_loader_Klass + * + * A Klass viewed as this closure becomes a node in a binary tree: + * + * Klass + * O + * / \ + * / \ + * [1] O O [2] + * + * We write the Klass and tag the artifacts in its closure (subtree) + * using preorder traversal by recursing the class_loader_Klass(es). * - * The weird naming is an effort to decrease the risk of name clashes. */ -static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp) { +static void do_write_klass(JfrCheckpointWriter* writer, CldPtr cld, KlassPtr klass, bool leakp) { assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); assert(klass != nullptr, "invariant"); writer->write(artifact_id(klass)); - ClassLoaderData* cld = get_cld(klass); writer->write(cld != nullptr ? cld_id(cld, leakp) : 0); writer->write(mark_symbol(klass, leakp)); writer->write(package_id(klass, leakp)); writer->write(klass->modifier_flags()); writer->write(klass->is_hidden()); - return 1; + if (!leakp) { + set_serialized(klass); + } +} + +static inline bool should_write_cld_klass(KlassPtr klass, bool leakp) { + return klass != nullptr && (leakp || IS_NOT_SERIALIZED(klass)); +} + +static void write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp, int& elements) { + assert(elements >= 0, "invariant"); + ClassLoaderData* cld = get_cld(klass); + do_write_klass(writer, cld, klass, leakp); + ++elements; + if (cld != nullptr) { + // Write the klass for the direct cld. + KlassPtr cld_klass = get_cld_klass(cld, leakp); + if (should_write_cld_klass(cld_klass, leakp)) { + write_klass(writer, cld_klass, leakp, elements); + } + } + KlassPtr mod_klass = get_module_cld_klass(klass, leakp); + if (should_write_cld_klass(mod_klass, leakp)) { + // Write the klass for the module cld. + write_klass(writer, mod_klass, leakp, elements); + } } +/* + * In C++03, functions used as template parameters must have external linkage; + * this restriction was removed in C++11. Change back to "static" and + * rename functions when C++11 becomes available. + * + * The weird naming is an effort to decrease the risk of name clashes. + */ int write__klass(JfrCheckpointWriter* writer, const void* k) { assert(k != nullptr, "invariant"); - KlassPtr klass = (KlassPtr)k; - set_serialized(klass); - return write_klass(writer, klass, false); + KlassPtr klass = static_cast(k); + int elements = 0; + write_klass(writer, klass, false, elements); + return elements; } int write__klass__leakp(JfrCheckpointWriter* writer, const void* k) { assert(k != nullptr, "invariant"); - KlassPtr klass = (KlassPtr)k; + KlassPtr klass = static_cast(k); CLEAR_LEAKP(klass); - return write_klass(writer, klass, true); + int elements = 0; + write_klass(writer, klass, true, elements); + return elements; } -static bool is_implied(const Klass* klass) { - assert(klass != nullptr, "invariant"); - return klass->is_subclass_of(vmClasses::ClassLoader_klass()) || klass == vmClasses::Object_klass(); -} +static int primitives_count = 9; -static void do_klass(Klass* klass) { - assert(klass != nullptr, "invariant"); - assert(_flushpoint ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass), "invariant"); - assert(_subsystem_callback != nullptr, "invariant"); - _subsystem_callback->do_artifact(klass); +static const char* primitive_name(KlassPtr type_array_klass) { + switch (type_array_klass->name()->base()[1]) { + case JVM_SIGNATURE_BOOLEAN: return "boolean"; + case JVM_SIGNATURE_BYTE: return "byte"; + case JVM_SIGNATURE_CHAR: return "char"; + case JVM_SIGNATURE_SHORT: return "short"; + case JVM_SIGNATURE_INT: return "int"; + case JVM_SIGNATURE_LONG: return "long"; + case JVM_SIGNATURE_FLOAT: return "float"; + case JVM_SIGNATURE_DOUBLE: return "double"; + } + assert(false, "invalid type array klass"); + return nullptr; } +static Symbol* primitive_symbol(KlassPtr type_array_klass) { + if (type_array_klass == nullptr) { + // void.class + static Symbol* const void_class_name = SymbolTable::probe("void", 4); + assert(void_class_name != nullptr, "invariant"); + return void_class_name; + } + const char* const primitive_type_str = primitive_name(type_array_klass); + assert(primitive_type_str != nullptr, "invariant"); + Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, + (int)strlen(primitive_type_str)); + assert(primitive_type_sym != nullptr, "invariant"); + return primitive_type_sym; +} static traceid primitive_id(KlassPtr array_klass) { if (array_klass == nullptr) { @@ -271,148 +450,69 @@ static void write_primitive(JfrCheckpointWriter* writer, KlassPtr type_array_kla writer->write(false); } -static void do_loader_klass(const Klass* klass) { - if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) { - if (_leakp_writer != nullptr) { - SET_LEAKP(klass); - } - SET_TRANSIENT(klass); - _subsystem_callback->do_artifact(klass); - } -} - -static bool register_klass_unload(Klass* klass) { - assert(klass != nullptr, "invariant"); - return JfrKlassUnloading::on_unload(klass); -} - -static void do_unloading_klass(Klass* klass) { - assert(klass != nullptr, "invariant"); - assert(_subsystem_callback != nullptr, "invariant"); - if (register_klass_unload(klass)) { - _subsystem_callback->do_artifact(klass); - do_loader_klass(klass->class_loader_data()->class_loader_klass()); - } -} - -/* - * Abstract klasses are filtered out unconditionally. - * If a klass is not yet initialized, i.e yet to run its - * it is also filtered out so we don't accidentally - * trigger initialization. - */ -static bool is_classloader_klass_allowed(const Klass* k) { - assert(k != nullptr, "invariant"); - return !(k->is_abstract() || k->should_be_initialized()); -} - -static void do_classloaders() { - for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) { - Klass* subk = iter.klass(); - if (is_classloader_klass_allowed(subk)) { - do_loader_klass(subk); - } - } +static bool is_initial_typeset_for_chunk() { + return _initial_type_set && !unloading(); } -static int primitives_count = 9; - // A mirror representing a primitive class (e.g. int.class) has no reified Klass*, // instead it has an associated TypeArrayKlass* (e.g. int[].class). // We can use the TypeArrayKlass* as a proxy for deriving the id of the primitive class. // The exception is the void.class, which has neither a Klass* nor a TypeArrayKlass*. // It will use a reserved constant. static void do_primitives() { - // Only write the primitive classes once per chunk. - if (is_initial_typeset_for_chunk()) { - write_primitive(_writer, Universe::boolArrayKlassObj()); - write_primitive(_writer, Universe::byteArrayKlassObj()); - write_primitive(_writer, Universe::charArrayKlassObj()); - write_primitive(_writer, Universe::shortArrayKlassObj()); - write_primitive(_writer, Universe::intArrayKlassObj()); - write_primitive(_writer, Universe::longArrayKlassObj()); - write_primitive(_writer, Universe::floatArrayKlassObj()); - write_primitive(_writer, Universe::doubleArrayKlassObj()); - write_primitive(_writer, nullptr); // void.class - } + assert(is_initial_typeset_for_chunk(), "invariant"); + write_primitive(_writer, Universe::boolArrayKlassObj()); + write_primitive(_writer, Universe::byteArrayKlassObj()); + write_primitive(_writer, Universe::charArrayKlassObj()); + write_primitive(_writer, Universe::shortArrayKlassObj()); + write_primitive(_writer, Universe::intArrayKlassObj()); + write_primitive(_writer, Universe::longArrayKlassObj()); + write_primitive(_writer, Universe::floatArrayKlassObj()); + write_primitive(_writer, Universe::doubleArrayKlassObj()); + write_primitive(_writer, nullptr); // void.class } -static void do_object() { - SET_TRANSIENT(vmClasses::Object_klass()); - do_klass(vmClasses::Object_klass()); -} - -static void do_klasses() { - if (_class_unload) { - ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass); - return; - } - JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch()); - do_classloaders(); - do_primitives(); - do_object(); -} - -template -static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) { - assert(callback != nullptr, "invariant"); - assert(value != nullptr, "invariant"); - if (USED_PREVIOUS_EPOCH(value)) { - callback->do_artifact(value); - } - if (IS_SERIALIZED(value)) { - CLEAR_SERIALIZED(value); - } - assert(IS_NOT_SERIALIZED(value), "invariant"); -} - -static void do_previous_epoch_klass(JfrArtifactClosure* callback, const Klass* value) { - assert(callback != nullptr, "invariant"); - assert(value != nullptr, "invariant"); - if (USED_PREVIOUS_EPOCH(value)) { - callback->do_artifact(value); +static void do_unloading_klass(Klass* klass) { + assert(klass != nullptr, "invariant"); + assert(_subsystem_callback != nullptr, "invariant"); + if (JfrKlassUnloading::on_unload(klass)) { + _subsystem_callback->do_artifact(klass); } } -static void do_klass_on_clear(Klass* klass) { +static void do_klass(Klass* klass) { assert(klass != nullptr, "invariant"); + assert(used(klass), "invariant"); assert(_subsystem_callback != nullptr, "invariant"); - do_previous_epoch_klass(_subsystem_callback, klass); + _subsystem_callback->do_artifact(klass); } -static void do_loader_klass_on_clear(const Klass* klass) { - if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) { - if (_leakp_writer != nullptr) { - SET_LEAKP(klass); - } - SET_TRANSIENT(klass); - do_previous_epoch_klass(_subsystem_callback, klass); +static void do_klasses() { + if (unloading()) { + ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass); + return; } -} - -static void do_classloaders_on_clear() { - for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) { - Klass* subk = iter.klass(); - if (is_classloader_klass_allowed(subk)) { - do_loader_klass_on_clear(subk); - } + if (is_initial_typeset_for_chunk()) { + // Only write the primitive classes once per chunk. + do_primitives(); } + JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch()); } -static void do_object_on_clear() { - SET_TRANSIENT(vmClasses::Object_klass()); - do_klass_on_clear(vmClasses::Object_klass()); +static void do_klass_on_clear(Klass* klass) { + do_artifact(klass); } static void do_all_klasses() { ClassLoaderDataGraph::classes_do(&do_klass_on_clear); - do_classloaders_on_clear(); - do_object_on_clear(); } +// KlassWriter. typedef SerializePredicate KlassPredicate; typedef JfrPredicatedTypeWriterImplHost KlassWriterImpl; typedef JfrTypeWriterHost KlassWriter; + +// Klass registration. typedef CompositeFunctor KlassWriterRegistration; typedef JfrArtifactCallbackHost KlassCallback; @@ -422,29 +522,31 @@ class LeakPredicate { LeakPredicate(bool class_unload) {} bool operator()(const Klass* klass) { assert(klass != nullptr, "invariant"); - return IS_LEAKP(klass) || is_implied(klass); + return IS_LEAKP(klass); } }; +// KlassWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakKlassPredicate; typedef JfrPredicatedTypeWriterImplHost LeakKlassWriterImpl; typedef JfrTypeWriterHost LeakKlassWriter; +// Composite KlassWriter with registration. typedef CompositeFunctor CompositeKlassWriter; typedef CompositeFunctor CompositeKlassWriterRegistration; typedef JfrArtifactCallbackHost CompositeKlassCallback; -static bool write_klasses() { +static void write_klasses() { assert(!_artifacts->has_klass_entries(), "invariant"); assert(_writer != nullptr, "invariant"); KlassArtifactRegistrator reg(_artifacts); - KlassWriter kw(_writer, _class_unload); + KlassWriter kw(_writer, unloading()); KlassWriterRegistration kwr(&kw, ®); if (_leakp_writer == nullptr) { KlassCallback callback(&_subsystem_callback, &kwr); do_klasses(); } else { - LeakKlassWriter lkw(_leakp_writer, _class_unload); + LeakKlassWriter lkw(_leakp_writer, unloading()); CompositeKlassWriter ckw(&lkw, &kw); CompositeKlassWriterRegistration ckwr(&ckw, ®); CompositeKlassCallback callback(&_subsystem_callback, &ckwr); @@ -455,32 +557,26 @@ static bool write_klasses() { // their count is not automatically incremented. kw.add(primitives_count); } - if (is_complete()) { - return false; - } _artifacts->tally(kw); - return true; } -static bool write_klasses_on_clear() { +static void write_klasses_on_clear() { assert(!_artifacts->has_klass_entries(), "invariant"); assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); KlassArtifactRegistrator reg(_artifacts); - KlassWriter kw(_writer, _class_unload); + KlassWriter kw(_writer, unloading()); KlassWriterRegistration kwr(&kw, ®); - LeakKlassWriter lkw(_leakp_writer, _class_unload); + LeakKlassWriter lkw(_leakp_writer, unloading()); CompositeKlassWriter ckw(&lkw, &kw); CompositeKlassWriterRegistration ckwr(&ckw, ®); CompositeKlassCallback callback(&_subsystem_callback, &ckwr); do_all_klasses(); - if (is_complete()) { - return false; - } _artifacts->tally(kw); - return true; } +/***** Packages *****/ + static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); @@ -494,98 +590,101 @@ static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { int write__package(JfrCheckpointWriter* writer, const void* p) { assert(p != nullptr, "invariant"); - PkgPtr pkg = (PkgPtr)p; + PkgPtr pkg = static_cast(p); set_serialized(pkg); return write_package(writer, pkg, false); } int write__package__leakp(JfrCheckpointWriter* writer, const void* p) { assert(p != nullptr, "invariant"); - PkgPtr pkg = (PkgPtr)p; + PkgPtr pkg = static_cast(p); CLEAR_LEAKP(pkg); return write_package(writer, pkg, true); } -static void do_package(PackageEntry* entry) { - do_previous_epoch_artifact(_subsystem_callback, entry); -} - -static void do_packages() { - ClassLoaderDataGraph::packages_do(&do_package); -} - -class PackageFieldSelector { - public: - typedef PkgPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - return klass->package(); - } -}; +// PackageWriter. typedef SerializePredicate PackagePredicate; typedef JfrPredicatedTypeWriterImplHost PackageWriterImpl; typedef JfrTypeWriterHost PackageWriter; -typedef CompositeFunctor > PackageWriterWithClear; +typedef JfrArtifactCallbackHost PackageCallback; + +// PackageWriter used during flush or unloading i.e. the current epoch. typedef KlassToFieldEnvelope KlassPackageWriter; -typedef JfrArtifactCallbackHost PackageCallback; +// PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > PackageWriterWithClear; +typedef JfrArtifactCallbackHost PackageClearCallback; + +// PackageWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakPackagePredicate; typedef JfrPredicatedTypeWriterImplHost LeakPackageWriterImpl; typedef JfrTypeWriterHost LeakPackageWriter; +// Composite PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch. typedef CompositeFunctor CompositePackageWriter; -typedef KlassToFieldEnvelope KlassCompositePackageWriter; -typedef KlassToFieldEnvelope KlassPackageWriterWithClear; typedef CompositeFunctor > CompositePackageWriterWithClear; -typedef JfrArtifactCallbackHost CompositePackageCallback; +typedef JfrArtifactCallbackHost CompositePackageClearCallback; + +static void do_package(PackageEntry* pkg) { + do_artifact(pkg); +} + +static void do_all_packages() { + ClassLoaderDataGraph::packages_do(&do_package); +} + +static void do_all_packages(PackageWriter& pw) { + do_all_packages(); + _artifacts->tally(pw); +} + +static void do_packages(PackageWriter& pw) { + KlassPackageWriter kpw(&pw); + _artifacts->iterate_klasses(kpw); + _artifacts->tally(pw); +} + +static void write_packages_with_leakp(PackageWriter& pw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakPackageWriter lpw(_leakp_writer, unloading()); + CompositePackageWriter cpw(&lpw, &pw); + ClearArtifact clear; + CompositePackageWriterWithClear cpwwc(&cpw, &clear); + CompositePackageClearCallback callback(&_subsystem_callback, &cpwwc); + do_all_packages(pw); +} static void write_packages() { assert(_writer != nullptr, "invariant"); - PackageWriter pw(_writer, _class_unload); - KlassPackageWriter kpw(&pw); + PackageWriter pw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kpw); - _artifacts->tally(pw); + do_packages(pw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kpw); ClearArtifact clear; PackageWriterWithClear pwwc(&pw, &clear); - PackageCallback callback(&_subsystem_callback, &pwwc); - do_packages(); - } else { - LeakPackageWriter lpw(_leakp_writer, _class_unload); - CompositePackageWriter cpw(&lpw, &pw); - KlassCompositePackageWriter kcpw(&cpw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositePackageWriterWithClear cpwwc(&cpw, &clear); - CompositePackageCallback callback(&_subsystem_callback, &cpwwc); - do_packages(); + PackageClearCallback callback(&_subsystem_callback, &pwwc); + do_all_packages(pw); + return; } - _artifacts->tally(pw); + write_packages_with_leakp(pw); } static void write_packages_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - PackageWriter pw(_writer, _class_unload); - KlassPackageWriter kpw(&pw); - LeakPackageWriter lpw(_leakp_writer, _class_unload); - CompositePackageWriter cpw(&lpw, &pw); - KlassCompositePackageWriter kcpw(&cpw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositePackageWriterWithClear cpwwc(&cpw, &clear); - CompositePackageCallback callback(&_subsystem_callback, &cpwwc); - do_packages(); - _artifacts->tally(pw); + PackageWriter pw(_writer, unloading()); + write_packages_with_leakp(pw); } +/***** Modules *****/ + static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { assert(mod != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); @@ -599,99 +698,101 @@ static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { int write__module(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - ModPtr mod = (ModPtr)m; + ModPtr mod = static_cast(m); set_serialized(mod); return write_module(writer, mod, false); } int write__module__leakp(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - ModPtr mod = (ModPtr)m; + ModPtr mod = static_cast(m); CLEAR_LEAKP(mod); return write_module(writer, mod, true); } -static void do_module(ModuleEntry* entry) { - do_previous_epoch_artifact(_subsystem_callback, entry); -} - -static void do_modules() { - ClassLoaderDataGraph::modules_do(&do_module); -} - -class ModuleFieldSelector { - public: - typedef ModPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - PkgPtr pkg = klass->package(); - return pkg != nullptr ? pkg->module() : nullptr; - } -}; - +// ModuleWriter. typedef SerializePredicate ModulePredicate; typedef JfrPredicatedTypeWriterImplHost ModuleWriterImpl; typedef JfrTypeWriterHost ModuleWriter; -typedef CompositeFunctor > ModuleWriterWithClear; -typedef JfrArtifactCallbackHost ModuleCallback; +typedef JfrArtifactCallbackHost ModuleCallback; + +// ModuleWriter used during flush or unloading i.e. the current epoch. typedef KlassToFieldEnvelope KlassModuleWriter; +// ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > ModuleWriterWithClear; +typedef JfrArtifactCallbackHost ModuleClearCallback; + +// ModuleWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakModulePredicate; typedef JfrPredicatedTypeWriterImplHost LeakModuleWriterImpl; typedef JfrTypeWriterHost LeakModuleWriter; +// Composite ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch. typedef CompositeFunctor CompositeModuleWriter; -typedef KlassToFieldEnvelope KlassCompositeModuleWriter; typedef CompositeFunctor > CompositeModuleWriterWithClear; -typedef JfrArtifactCallbackHost CompositeModuleCallback; +typedef JfrArtifactCallbackHost CompositeModuleClearCallback; + +static void do_module(ModuleEntry* mod) { + do_artifact(mod); +} + +static void do_all_modules() { + ClassLoaderDataGraph::modules_do(&do_module); +} + +static void do_all_modules(ModuleWriter& mw) { + do_all_modules(); + _artifacts->tally(mw); +} + +static void do_modules(ModuleWriter& mw) { + KlassModuleWriter kmw(&mw); + _artifacts->iterate_klasses(kmw); + _artifacts->tally(mw); +} + +static void write_modules_with_leakp(ModuleWriter& mw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakModuleWriter lmw(_leakp_writer, unloading()); + CompositeModuleWriter cmw(&lmw, &mw); + ClearArtifact clear; + CompositeModuleWriterWithClear cmwwc(&cmw, &clear); + CompositeModuleClearCallback callback(&_subsystem_callback, &cmwwc); + do_all_modules(mw); +} static void write_modules() { assert(_writer != nullptr, "invariant"); - ModuleWriter mw(_writer, _class_unload); - KlassModuleWriter kmw(&mw); + ModuleWriter mw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kmw); - _artifacts->tally(mw); + do_modules(mw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kmw); ClearArtifact clear; ModuleWriterWithClear mwwc(&mw, &clear); - ModuleCallback callback(&_subsystem_callback, &mwwc); - do_modules(); - } else { - LeakModuleWriter lmw(_leakp_writer, _class_unload); - CompositeModuleWriter cmw(&lmw, &mw); - KlassCompositeModuleWriter kcpw(&cmw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositeModuleWriterWithClear cmwwc(&cmw, &clear); - CompositeModuleCallback callback(&_subsystem_callback, &cmwwc); - do_modules(); + ModuleClearCallback callback(&_subsystem_callback, &mwwc); + do_all_modules(mw); + return; } - _artifacts->tally(mw); + write_modules_with_leakp(mw); } static void write_modules_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - ModuleWriter mw(_writer, _class_unload); - KlassModuleWriter kmw(&mw); - LeakModuleWriter lmw(_leakp_writer, _class_unload); - CompositeModuleWriter cmw(&lmw, &mw); - KlassCompositeModuleWriter kcpw(&cmw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositeModuleWriterWithClear cmwwc(&cmw, &clear); - CompositeModuleCallback callback(&_subsystem_callback, &cmwwc); - do_modules(); - _artifacts->tally(mw); + ModuleWriter mw(_writer, unloading()); + write_modules_with_leakp(mw); } -static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { +/***** ClassLoaderData - CLD *****/ + +static int write_cld(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { assert(cld != nullptr, "invariant"); // class loader type const Klass* class_loader_klass = cld->class_loader_klass(); @@ -701,7 +802,7 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp writer->write((traceid)0); // class loader type id (absence of) writer->write(get_bootstrap_name(leakp)); // maps to synthetic name -> "bootstrap" } else { - assert(_class_unload ? true : IS_SERIALIZED(class_loader_klass), "invariant"); + assert(IS_SERIALIZED(class_loader_klass), "invariant"); writer->write(artifact_id(cld)); // class loader instance id writer->write(artifact_id(class_loader_klass)); // class loader type id writer->write(mark_symbol(cld->name(), leakp)); // class loader instance name @@ -709,146 +810,127 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp return 1; } -int write__classloader(JfrCheckpointWriter* writer, const void* c) { +int write__cld(JfrCheckpointWriter* writer, const void* c) { assert(c != nullptr, "invariant"); - CldPtr cld = (CldPtr)c; + CldPtr cld = static_cast(c); set_serialized(cld); - return write_classloader(writer, cld, false); + return write_cld(writer, cld, false); } -int write__classloader__leakp(JfrCheckpointWriter* writer, const void* c) { +int write__cld__leakp(JfrCheckpointWriter* writer, const void* c) { assert(c != nullptr, "invariant"); - CldPtr cld = (CldPtr)c; + CldPtr cld = static_cast(c); CLEAR_LEAKP(cld); - return write_classloader(writer, cld, true); + return write_cld(writer, cld, true); } -static void do_class_loader_data(ClassLoaderData* cld) { - do_previous_epoch_artifact(_subsystem_callback, cld); -} +// CldWriter. +typedef SerializePredicate CldPredicate; +typedef JfrPredicatedTypeWriterImplHost CldWriterImpl; +typedef JfrTypeWriterHost CldWriter; +typedef JfrArtifactCallbackHost CldCallback; -class KlassCldFieldSelector { - public: - typedef CldPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - return get_cld(klass); - } -}; +// CldWriter used during flush or unloading i.e. the current epoch. +typedef KlassToFieldEnvelope KlassCldWriter; +typedef KlassToFieldEnvelope ModuleCldWriter; +typedef CompositeFunctor KlassAndModuleCldWriter; -class ModuleCldFieldSelector { -public: - typedef CldPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - ModPtr mod = ModuleFieldSelector::select(klass); - return mod != nullptr ? mod->loader_data() : nullptr; - } -}; +// CldWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > CldWriterWithClear; +typedef JfrArtifactCallbackHost CldClearCallback; + +// CldWriter for leakp. Only used during start or rotation, i.e. the previous epoch. +typedef LeakPredicate LeakCldPredicate; +typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl; +typedef JfrTypeWriterHost LeakCldWriter; + +// Composite CldWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor CompositeCldWriter; +typedef CompositeFunctor > CompositeCldWriterWithClear; +typedef JfrArtifactCallbackHost CompositeCldClearCallback; class CLDCallback : public CLDClosure { public: - CLDCallback() {} void do_cld(ClassLoaderData* cld) { assert(cld != nullptr, "invariant"); - if (cld->has_class_mirror_holder()) { - return; + if (!cld->has_class_mirror_holder()) { + do_artifact(cld); } - do_class_loader_data(cld); } }; -static void do_class_loaders() { +static void do_all_clds() { CLDCallback cld_cb; ClassLoaderDataGraph::loaded_cld_do(&cld_cb); } -typedef SerializePredicate CldPredicate; -typedef JfrPredicatedTypeWriterImplHost CldWriterImpl; -typedef JfrTypeWriterHost CldWriter; -typedef CompositeFunctor > CldWriterWithClear; -typedef JfrArtifactCallbackHost CldCallback; -typedef KlassToFieldEnvelope KlassCldWriter; -typedef KlassToFieldEnvelope ModuleCldWriter; -typedef CompositeFunctor KlassAndModuleCldWriter; - -typedef LeakPredicate LeakCldPredicate; -typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl; -typedef JfrTypeWriterHost LeakCldWriter; - -typedef CompositeFunctor CompositeCldWriter; -typedef KlassToFieldEnvelope KlassCompositeCldWriter; -typedef KlassToFieldEnvelope ModuleCompositeCldWriter; -typedef CompositeFunctor KlassAndModuleCompositeCldWriter; -typedef CompositeFunctor > CompositeCldWriterWithClear; -typedef JfrArtifactCallbackHost CompositeCldCallback; +static void do_all_clds(CldWriter& cldw) { + do_all_clds(); + _artifacts->tally(cldw); +} -static void write_classloaders() { - assert(_writer != nullptr, "invariant"); - CldWriter cldw(_writer, _class_unload); +static void do_clds(CldWriter& cldw) { KlassCldWriter kcw(&cldw); ModuleCldWriter mcw(&cldw); KlassAndModuleCldWriter kmcw(&kcw, &mcw); + _artifacts->iterate_klasses(kmcw); + _artifacts->tally(cldw); +} + +static void write_clds_with_leakp(CldWriter& cldw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakCldWriter lcldw(_leakp_writer, unloading()); + CompositeCldWriter ccldw(&lcldw, &cldw); + ClearArtifact clear; + CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); + CompositeCldClearCallback callback(&_subsystem_callback, &ccldwwc); + do_all_clds(cldw); +} + +static void write_clds() { + assert(_writer != nullptr, "invariant"); + CldWriter cldw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kmcw); - _artifacts->tally(cldw); + do_clds(cldw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kmcw); ClearArtifact clear; CldWriterWithClear cldwwc(&cldw, &clear); - CldCallback callback(&_subsystem_callback, &cldwwc); - do_class_loaders(); - } else { - LeakCldWriter lcldw(_leakp_writer, _class_unload); - CompositeCldWriter ccldw(&lcldw, &cldw); - KlassCompositeCldWriter kccldw(&ccldw); - ModuleCompositeCldWriter mccldw(&ccldw); - KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw); - _artifacts->iterate_klasses(kmccldw); - ClearArtifact clear; - CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); - CompositeCldCallback callback(&_subsystem_callback, &ccldwwc); - do_class_loaders(); + CldClearCallback callback(&_subsystem_callback, &cldwwc); + do_all_clds(cldw); + return; } - _artifacts->tally(cldw); + write_clds_with_leakp(cldw); } -static void write_classloaders_on_clear() { +static void write_clds_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); - CldWriter cldw(_writer, _class_unload); - KlassCldWriter kcw(&cldw); - ModuleCldWriter mcw(&cldw); - KlassAndModuleCldWriter kmcw(&kcw, &mcw); - LeakCldWriter lcldw(_leakp_writer, _class_unload); - CompositeCldWriter ccldw(&lcldw, &cldw); - KlassCompositeCldWriter kccldw(&ccldw); - ModuleCompositeCldWriter mccldw(&ccldw); - KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw); - _artifacts->iterate_klasses(kmccldw); - ClearArtifact clear; - CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); - CompositeCldCallback callback(&_subsystem_callback, &ccldwwc); - do_class_loaders(); - _artifacts->tally(cldw); + assert(previous_epoch(), "invariant"); + CldWriter cldw(_writer, unloading()); + write_clds_with_leakp(cldw); } -static u1 get_visibility(MethodPtr method) { - assert(method != nullptr, "invariant"); - return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; -} +/***** Methods *****/ template <> void set_serialized(MethodPtr method) { assert(method != nullptr, "invariant"); - SET_METHOD_SERIALIZED(method); - assert(METHOD_IS_SERIALIZED(method), "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); } + assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant"); + SET_METHOD_SERIALIZED(method); + assert(METHOD_IS_SERIALIZED(method), "invariant"); +} + +static inline u1 get_visibility(MethodPtr method) { + assert(method != nullptr, "invariant"); + return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; } static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leakp) { @@ -857,58 +939,37 @@ 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); + assert(METHOD_IS_NOT_SERIALIZED(method), "invariant"); 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 +979,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 +999,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 +1026,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 +1089,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 +1110,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 +1138,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 +1160,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 +1224,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 +1242,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/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); From d2d58dd6a8ec366a4bc3eb12a253b252de24557e Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Wed, 10 Jan 2024 13:13:32 +0000 Subject: [PATCH 058/153] 8322324: java/foreign/TestStubAllocFailure.java times out while waiting for forked process 8322637: java/foreign/critical/TestCriticalUpcall.java timed out Reviewed-by: mcimadamore --- test/jdk/java/foreign/UpcallTestHelper.java | 29 ++++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) 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 Date: Wed, 10 Jan 2024 13:25:43 +0000 Subject: [PATCH 059/153] 8323508: Remove TestGCLockerWithShenandoah.java line from TEST.groups Reviewed-by: dholmes, shade, tschatzl --- test/hotspot/jtreg/TEST.groups | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4573c0ebb9b9d..27956797948ed 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -356,7 +356,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 From 2806adee2d8cca6bc215f285888631799bd02eac Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Wed, 10 Jan 2024 14:07:57 +0000 Subject: [PATCH 060/153] 8321685: Missing ResourceMark in code called from JvmtiEnvBase::get_vthread_jvf Reviewed-by: amenkov, cjplummer --- src/hotspot/share/prims/jvmtiEnvBase.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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; From 16170678a72dbd7eecf55c21a426fb6179362fba Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 10 Jan 2024 15:03:21 +0000 Subject: [PATCH 061/153] 8323331: fix typo hpage_pdm_size Reviewed-by: shade, mdoerr --- src/hotspot/os/linux/os_linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 5117ccac84bb1..73785461df65e 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); From 2174f6646e8897f7e3991141a743c047c6e57026 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Jan 2024 15:18:57 +0000 Subject: [PATCH 062/153] 8323005: Parallel: Refactor PSPromotionManager::claim_or_forward_depth Reviewed-by: tschatzl, rrich --- .../share/gc/parallel/psPromotionManager.cpp | 4 +--- .../gc/parallel/psPromotionManager.inline.hpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) 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); } From f0169341846360d202c973ec368fdc3c5bf1ae5d Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Jan 2024 15:19:09 +0000 Subject: [PATCH 063/153] 8323518: Parallel: Remove unused methods in psParallelCompact.hpp Reviewed-by: tschatzl --- .../share/gc/parallel/psParallelCompact.hpp | 83 ------------------- 1 file changed, 83 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 173c883c498d4..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(); @@ -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; @@ -563,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;) @@ -597,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()); @@ -695,14 +664,6 @@ 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 { @@ -725,14 +686,6 @@ 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 >= _heap_start, "bad addr"); - assert(addr <= _heap_end, "bad addr"); - return (size_t(addr) & BlockAddrOffsetMask) >> LogHeapWordSize; -} - inline size_t ParallelCompactData::addr_to_block_idx(const HeapWord* addr) const { @@ -747,19 +700,6 @@ 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 _heap_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 { @@ -768,20 +708,6 @@ ParallelCompactData::block_align_down(HeapWord* addr) const return (HeapWord*)(size_t(addr) & BlockAddrMask); } -inline HeapWord* -ParallelCompactData::block_align_up(HeapWord* addr) const -{ - assert(addr >= _heap_start, "bad addr"); - assert(addr <= _heap_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. // @@ -1170,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 From 475306b7576356ca8e5b93fa7fe1be6c4d15065e Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 10 Jan 2024 16:34:06 +0000 Subject: [PATCH 064/153] 7057369: (fs spec) FileStore getUsableSpace and getUnallocatedSpace could be clearer Reviewed-by: alanb --- .../share/classes/java/nio/file/FileStore.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 From b86c3b7a68335d57699ea3c5ec6d09a62ea9026a Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 10 Jan 2024 16:42:30 +0000 Subject: [PATCH 065/153] 8309218: java/util/concurrent/locks/Lock/OOMEInAQS.java still times out with ZGC, Generational ZGC, and SerialGC Reviewed-by: jpai, dholmes, alanb --- test/jdk/ProblemList-generational-zgc.txt | 3 +-- test/jdk/ProblemList-zgc.txt | 4 +--- test/jdk/java/util/concurrent/locks/Lock/OOMEInAQS.java | 5 +++-- 3 files changed, 5 insertions(+), 7 deletions(-) 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/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 { From a7db4fecebe98135d36c6f46e1fa60959adbe78b Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 10 Jan 2024 17:10:39 +0000 Subject: [PATCH 066/153] 8323428: Shenandoah: Unused memory in regions compacted during a full GC should be mangled Reviewed-by: ysr, kdnilsen, shade --- src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp | 3 +++ 1 file changed, 3 insertions(+) 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 From c96cbe481c86800b76e220374b24b6671984adb7 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Wed, 10 Jan 2024 17:29:55 +0000 Subject: [PATCH 067/153] 8313083: Print 'rss' and 'cache' as part of the container information Reviewed-by: sgehwolf --- src/hotspot/os/linux/cgroupSubsystem_linux.hpp | 2 ++ src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp | 11 +++++++++++ src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp | 2 ++ src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp | 12 ++++++++++++ src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp | 2 ++ src/hotspot/os/linux/osContainer_linux.cpp | 10 ++++++++++ src/hotspot/os/linux/osContainer_linux.hpp | 2 ++ src/hotspot/os/linux/os_linux.cpp | 2 ++ test/hotspot/jtreg/containers/docker/TestMisc.java | 4 +++- 9 files changed, 46 insertions(+), 1 deletion(-) 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 73785461df65e..3a170edd697a0 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -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); 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) { From 5ba69e17340cf44194c080a38219c6e150418fcf Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 10 Jan 2024 17:52:50 +0000 Subject: [PATCH 068/153] 8322477: order of subclasses in the permits clause can differ between compilations Reviewed-by: jlahoda --- .../com/sun/tools/javac/code/Symbol.java | 40 ++++++++++++++-- .../com/sun/tools/javac/code/Types.java | 2 +- .../com/sun/tools/javac/comp/Attr.java | 46 +++++++++---------- .../com/sun/tools/javac/comp/Flow.java | 4 +- .../com/sun/tools/javac/comp/TypeEnter.java | 4 +- .../com/sun/tools/javac/jvm/ClassReader.java | 4 +- .../com/sun/tools/javac/jvm/ClassWriter.java | 8 ++-- .../JavacProcessingEnvironment.java | 2 +- .../sealed/SealedDiffConfigurationsTest.java | 35 +++++++++++++- 9 files changed, 106 insertions(+), 39 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index 6464afdfff899..2bb36eeded215 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -27,6 +27,7 @@ import java.lang.annotation.Annotation; import java.lang.annotation.Inherited; +import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -1303,10 +1304,12 @@ public static class ClassSymbol extends TypeSymbol implements TypeElement { // sealed classes related fields /** The classes, or interfaces, permitted to extend this class, or interface */ - public List permitted; + private java.util.List permitted; public boolean isPermittedExplicit = false; + private record PermittedClassWithPos(Symbol permittedClass, int pos) {} + public ClassSymbol(long flags, Name name, Type type, Symbol owner) { super(TYP, flags, name, type, owner); this.members_field = null; @@ -1315,7 +1318,7 @@ public ClassSymbol(long flags, Name name, Type type, Symbol owner) { this.sourcefile = null; this.classfile = null; this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType(); - this.permitted = List.nil(); + this.permitted = new ArrayList<>(); } public ClassSymbol(long flags, Name name, Symbol owner) { @@ -1327,6 +1330,37 @@ public ClassSymbol(long flags, Name name, Symbol owner) { this.type.tsym = this; } + public void addPermittedSubclass(ClassSymbol csym, int pos) { + Assert.check(!isPermittedExplicit); + // we need to insert at the right pos + PermittedClassWithPos element = new PermittedClassWithPos(csym, pos); + int index = Collections.binarySearch(permitted, element, java.util.Comparator.comparing(PermittedClassWithPos::pos)); + if (index < 0) { + index = -index - 1; + } + permitted.add(index, element); + } + + public boolean isPermittedSubclass(Symbol csym) { + for (PermittedClassWithPos permittedClassWithPos : permitted) { + if (permittedClassWithPos.permittedClass.equals(csym)) { + return true; + } + } + return false; + } + + public void clearPermittedSubclasses() { + permitted.clear(); + } + + public void setPermittedSubclasses(List permittedSubs) { + permitted.clear(); + for (Symbol csym : permittedSubs) { + permitted.add(new PermittedClassWithPos(csym, 0)); + } + } + /** The Java source which this symbol represents. */ public String toString() { @@ -1643,7 +1677,7 @@ public boolean isRecord() { @DefinedBy(Api.LANGUAGE_MODEL) public List getPermittedSubclasses() { - return permitted.map(s -> s.type); + return permitted.stream().map(s -> s.permittedClass().type).collect(List.collector()); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index d6ff37b3e53e2..7af1193c6ce3a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -1701,7 +1701,7 @@ private boolean areDisjoint(ClassSymbol ts, ClassSymbol ss) { // permitted subtypes have to be disjoint with the other symbol ClassSymbol sealedOne = ts.isSealed() ? ts : ss; ClassSymbol other = sealedOne == ts ? ss : ts; - return sealedOne.permitted.stream().allMatch(sym -> areDisjoint((ClassSymbol)sym, other)); + return sealedOne.getPermittedSubclasses().stream().allMatch(type -> areDisjoint((ClassSymbol)type.tsym, other)); } return false; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 342ccb267981b..bcc1645293518 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5383,58 +5383,58 @@ void attribClass(ClassSymbol c) throws CompletionFailure { if (c.isSealed() && !c.isEnum() && !c.isPermittedExplicit && - c.permitted.isEmpty()) { + c.getPermittedSubclasses().isEmpty()) { log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.SealedClassMustHaveSubclasses); } if (c.isSealed()) { Set permittedTypes = new HashSet<>(); boolean sealedInUnnamed = c.packge().modle == syms.unnamedModule || c.packge().modle == syms.noModule; - for (Symbol subTypeSym : c.permitted) { + for (Type subType : c.getPermittedSubclasses()) { boolean isTypeVar = false; - if (subTypeSym.type.getTag() == TYPEVAR) { + if (subType.getTag() == TYPEVAR) { isTypeVar = true; //error recovery - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), - Errors.InvalidPermitsClause(Fragments.IsATypeVariable(subTypeSym.type))); + log.error(TreeInfo.diagnosticPositionFor(subType.tsym, env.tree), + Errors.InvalidPermitsClause(Fragments.IsATypeVariable(subType))); } - if (subTypeSym.isAnonymous() && !c.isEnum()) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.LocalClassesCantExtendSealed(Fragments.Anonymous)); + if (subType.tsym.isAnonymous() && !c.isEnum()) { + log.error(TreeInfo.diagnosticPositionFor(subType.tsym, env.tree), Errors.LocalClassesCantExtendSealed(Fragments.Anonymous)); } - if (permittedTypes.contains(subTypeSym)) { + if (permittedTypes.contains(subType.tsym)) { DiagnosticPosition pos = env.enclClass.permitting.stream() - .filter(permittedExpr -> TreeInfo.diagnosticPositionFor(subTypeSym, permittedExpr, true) != null) + .filter(permittedExpr -> TreeInfo.diagnosticPositionFor(subType.tsym, permittedExpr, true) != null) .limit(2).collect(List.collector()).get(1); - log.error(pos, Errors.InvalidPermitsClause(Fragments.IsDuplicated(subTypeSym.type))); + log.error(pos, Errors.InvalidPermitsClause(Fragments.IsDuplicated(subType))); } else { - permittedTypes.add(subTypeSym); + permittedTypes.add(subType.tsym); } if (sealedInUnnamed) { - if (subTypeSym.packge() != c.packge()) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), + if (subType.tsym.packge() != c.packge()) { + log.error(TreeInfo.diagnosticPositionFor(subType.tsym, env.tree), Errors.ClassInUnnamedModuleCantExtendSealedInDiffPackage(c) ); } - } else if (subTypeSym.packge().modle != c.packge().modle) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), + } else if (subType.tsym.packge().modle != c.packge().modle) { + log.error(TreeInfo.diagnosticPositionFor(subType.tsym, env.tree), Errors.ClassInModuleCantExtendSealedInDiffModule(c, c.packge().modle) ); } - if (subTypeSym == c.type.tsym || types.isSuperType(subTypeSym.type, c.type)) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, ((JCClassDecl)env.tree).permitting), + if (subType.tsym == c.type.tsym || types.isSuperType(subType, c.type)) { + log.error(TreeInfo.diagnosticPositionFor(subType.tsym, ((JCClassDecl)env.tree).permitting), Errors.InvalidPermitsClause( - subTypeSym == c.type.tsym ? + subType.tsym == c.type.tsym ? Fragments.MustNotBeSameClass : - Fragments.MustNotBeSupertype(subTypeSym.type) + Fragments.MustNotBeSupertype(subType) ) ); } else if (!isTypeVar) { - boolean thisIsASuper = types.directSupertypes(subTypeSym.type) + boolean thisIsASuper = types.directSupertypes(subType) .stream() .anyMatch(d -> d.tsym == c); if (!thisIsASuper) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), - Errors.InvalidPermitsClause(Fragments.DoesntExtendSealed(subTypeSym.type))); + log.error(TreeInfo.diagnosticPositionFor(subType.tsym, env.tree), + Errors.InvalidPermitsClause(Fragments.DoesntExtendSealed(subType))); } } } @@ -5469,7 +5469,7 @@ void attribClass(ClassSymbol c) throws CompletionFailure { if (!c.type.isCompound()) { for (ClassSymbol supertypeSym : sealedSupers) { - if (!supertypeSym.permitted.contains(c.type.tsym)) { + if (!supertypeSym.isPermittedSubclass(c.type.tsym)) { log.error(TreeInfo.diagnosticPositionFor(c.type.tsym, env.tree), Errors.CantInheritFromSealed(supertypeSym)); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index dc02b434af02e..e1f5b6f38a0b6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -945,8 +945,8 @@ private Set allPermittedSubTypes(ClassSymbol root, Predicate baseEnv) { !supClass.isPermittedExplicit && supClassEnv != null && supClassEnv.toplevel == baseEnv.toplevel) { - supClass.permitted = supClass.permitted.append(sym); + supClass.addPermittedSubclass(sym, tree.pos); } } } @@ -932,7 +932,7 @@ private void fillPermits(JCClassDecl tree, Env baseEnv) { Type pt = attr.attribBase(permitted, baseEnv, false, false, false); permittedSubtypeSymbols.append(pt.tsym); } - sym.permitted = permittedSubtypeSymbols.toList(); + sym.setPermittedSubclasses(permittedSubtypeSymbols.toList()); } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index c64877f739229..47c7d9c7d4500 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1298,7 +1298,7 @@ protected void read(Symbol sym, int attrLen) { for (int i = 0; i < numberOfPermittedSubtypes; i++) { subtypes.add(poolReader.getClass(nextChar())); } - ((ClassSymbol)sym).permitted = subtypes.toList(); + ((ClassSymbol)sym).setPermittedSubclasses(subtypes.toList()); } } }, @@ -2930,7 +2930,7 @@ void readClass(ClassSymbol c) { for (int i = 0; i < methodCount; i++) skipMember(); readClassAttrs(c); - if (c.permitted != null && !c.permitted.isEmpty()) { + if (!c.getPermittedSubclasses().isEmpty()) { c.flags_field |= SEALED; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index aed63c44bb165..625d3fb890b3e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -922,11 +922,11 @@ private void listNested(Symbol sym, ListBuffer seen) { /** Write "PermittedSubclasses" attribute. */ int writePermittedSubclassesIfNeeded(ClassSymbol csym) { - if (csym.permitted.nonEmpty()) { + if (csym.getPermittedSubclasses().nonEmpty()) { int alenIdx = writeAttr(names.PermittedSubclasses); - databuf.appendChar(csym.permitted.size()); - for (Symbol c : csym.permitted) { - databuf.appendChar(poolWriter.putClass((ClassSymbol) c)); + databuf.appendChar(csym.getPermittedSubclasses().size()); + for (Type t : csym.getPermittedSubclasses()) { + databuf.appendChar(poolWriter.putClass((ClassSymbol) t.tsym)); } endAttr(alenIdx); return 1; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 028b8ba8f9f7d..c9fba2389012d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1643,7 +1643,7 @@ public void visitClassDef(JCClassDecl node) { originalAnnos.forEach(a -> visitAnnotation(a)); } // we should empty the list of permitted subclasses for next round - node.sym.permitted = List.nil(); + node.sym.clearPermittedSubclasses(); } node.sym = null; } 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")); + } } From c1282b57f50002edd08c93aed784390cca83b9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 10 Jan 2024 18:37:33 +0000 Subject: [PATCH 069/153] 8323540: assert((!((((method)->is_trace_flag_set(((1 << 4) << 8))))))) failed: invariant Reviewed-by: mikael --- src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 2d49c5aa405fb..8df2f6593efd2 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -953,7 +953,6 @@ static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leak int write__method(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); MethodPtr method = static_cast(m); - assert(METHOD_IS_NOT_SERIALIZED(method), "invariant"); set_serialized(method); return write_method(writer, method, false); } From 525063be90bc67257e5d9301a4270179c03ada9d Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 10 Jan 2024 18:46:56 +0000 Subject: [PATCH 070/153] 8322878: Including sealing information Class.toGenericString() Co-authored-by: Pavel Rappo Reviewed-by: rriggs --- .../share/classes/java/lang/Class.java | 53 +++++- .../java/lang/Class/GenericStringTest.java | 172 ++++++++++++++++-- 2 files changed, 205 insertions(+), 20 deletions(-) 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/test/jdk/java/lang/Class/GenericStringTest.java b/test/jdk/java/lang/Class/GenericStringTest.java index f117a44b4465c..71f39f602283f 100644 --- a/test/jdk/java/lang/Class/GenericStringTest.java +++ b/test/jdk/java/lang/Class/GenericStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, 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 @@ -23,9 +23,8 @@ /* * @test - * @bug 6298888 6992705 8161500 6304578 + * @bug 6298888 6992705 8161500 6304578 8322878 * @summary Check Class.toGenericString() - * @author Joseph D. Darcy */ import java.lang.reflect.*; @@ -37,25 +36,41 @@ public class GenericStringTest { public Map[] mixed = null; public Map[][] mixed2 = null; + private static record PlatformTestCase(Class clazz, String expected) {} + public static void main(String... args) throws ReflectiveOperationException { int failures = 0; String[][] nested = {{""}}; int[][] intArray = {{1}}; - Map, String> testCases = - Map.of(int.class, "int", - void.class, "void", - args.getClass(), "java.lang.String[]", - nested.getClass(), "java.lang.String[][]", - intArray.getClass(), "int[][]", - java.lang.Enum.class, "public abstract class java.lang.Enum>", - java.util.Map.class, "public abstract interface java.util.Map", - java.util.EnumMap.class, "public class java.util.EnumMap,V>", - java.util.EventListenerProxy.class, "public abstract class java.util.EventListenerProxy"); - - for (Map.Entry, String> testCase : testCases.entrySet()) { - failures += checkToGenericString(testCase.getKey(), testCase.getValue()); + List platformTestCases = + List.of(new PlatformTestCase(int.class, "int"), + new PlatformTestCase(void.class, "void"), + new PlatformTestCase(args.getClass(), "java.lang.String[]"), + new PlatformTestCase(nested.getClass(), "java.lang.String[][]"), + new PlatformTestCase(intArray.getClass(), "int[][]"), + + new PlatformTestCase(java.lang.Enum.class, + "public abstract class java.lang.Enum>"), + new PlatformTestCase(java.util.Map.class, + "public abstract interface java.util.Map"), + new PlatformTestCase(java.util.EnumMap.class, + "public class java.util.EnumMap,V>"), + new PlatformTestCase(java.util.EventListenerProxy.class, + "public abstract class java.util.EventListenerProxy"), + + // Sealed class + new PlatformTestCase(java.lang.ref.Reference.class, + "public abstract sealed class java.lang.ref.Reference"), + // non-sealed class + new PlatformTestCase(java.lang.ref.WeakReference.class, + "public non-sealed class java.lang.ref.WeakReference") + ); + + for (PlatformTestCase platformTestCase : platformTestCases) { + failures += checkToGenericString(platformTestCase.clazz, + platformTestCase.expected); } Field f = GenericStringTest.class.getDeclaredField("mixed"); @@ -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 {} + } +} From 3bd9042054116365323912ed5867b70936fe85c4 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 10 Jan 2024 18:54:02 +0000 Subject: [PATCH 071/153] 8320788: The system properties page is missing some properties Reviewed-by: iris, rriggs, bpb, joehw --- src/java.base/share/classes/java/lang/System.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 227982af9eaf6..39ecb2a6436ca 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -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 From d89602a53f173e4fc1e0aa10bb0ffdf7232456cb Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Wed, 10 Jan 2024 19:42:03 +0000 Subject: [PATCH 072/153] 8322982: CTW fails to build after 8308753 Reviewed-by: shade, phh --- test/hotspot/jtreg/testlibrary/ctw/Makefile | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) 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 From e70cb4e6c7fe131d585cfa3ff3b4dbeb4f9bbccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 10 Jan 2024 21:42:23 +0000 Subject: [PATCH 073/153] 8322565: (zipfs) Files.setPosixPermissions should preserve 'external file attributes' bits Reviewed-by: clanger, lancea --- .../classes/jdk/nio/zipfs/ZipFileSystem.java | 11 +- test/jdk/jdk/nio/zipfs/TestPosix.java | 161 ++++++++++++++---- 2 files changed, 136 insertions(+), 36 deletions(-) diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index 1924ccd11f86b..7b478151c43e8 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -644,7 +644,12 @@ void setPermissions(byte[] path, Set perms) throws IOExcept if (e.type == Entry.CEN) { e.type = Entry.COPY; // copy e } - e.posixPerms = perms == null ? -1 : ZipUtils.permsToFlags(perms); + if (perms == null) { + e.posixPerms = -1; + } else { + e.posixPerms = ZipUtils.permsToFlags(perms) | + (e.posixPerms & 0xFE00); // Preserve unrelated bits + } update(e); } finally { endWrite(); @@ -3008,7 +3013,7 @@ private void readCEN(ZipFileSystem zipfs, IndexNode inode) throws IOException { attrsEx = CENATX(cen, pos); */ if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) { - posixPerms = CENATX_PERMS(cen, pos) & 0xFFF; // 12 bits for setuid, setgid, sticky + perms + posixPerms = (CENATX_PERMS(cen, pos) & 0xFFFF); // 16 bits for file type, setuid, setgid, sticky + perms } locoff = CENOFF(cen, pos); pos += CENHDR; 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:"); } } From b530c0281b5082994065b10addeb8366ffa58e2f Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Thu, 11 Jan 2024 00:36:16 +0000 Subject: [PATCH 074/153] 8317804: com/sun/jdi/JdwpAllowTest.java fails on Alpine 3.17 / 3.18 Reviewed-by: cjplummer, mbaesken --- .../share/native/libdt_socket/socketTransport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c index d494a7ecb2cee..28eb403448f67 100644 --- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c +++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c @@ -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 @@ -752,7 +752,7 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, if (isEqualIPv6Addr(listenAddr, mappedAny)) { for (ai = addrInfo; ai != NULL; ai = ai->ai_next) { - if (isEqualIPv6Addr(listenAddr, in6addr_any)) { + if (isEqualIPv6Addr(ai, in6addr_any)) { listenAddr = ai; break; } From 26de9e247a6ed1c0b8b247d77514ed16905d7c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Thu, 11 Jan 2024 06:32:24 +0000 Subject: [PATCH 075/153] 8321616: Retire binary test vectors in test/jdk/java/util/zip/ZipFile 8322830: Add test case for ZipFile opening a ZIP with no entries Reviewed-by: lancea --- test/jdk/java/util/zip/CopyZipFile.java | 291 ++++++----- test/jdk/java/util/zip/ZipFile/Available.java | 37 -- test/jdk/java/util/zip/ZipFile/CopyJar.java | 48 -- .../java/util/zip/ZipFile/EnumAfterClose.java | 49 -- .../util/zip/ZipFile/EnumerateAfterClose.java | 94 ++++ .../util/zip/ZipFile/FinalizeInflater.java | 67 ++- .../java/util/zip/ZipFile/GetDirEntry.java | 43 -- .../java/util/zip/ZipFile/ReadAfterClose.java | 51 -- test/jdk/java/util/zip/ZipFile/ReadZip.java | 476 ++++++++++++------ .../util/zip/ZipFile/ReleaseInflater.java | 79 ++- .../zip/ZipFile/StreamZipEntriesTest.java | 157 ++++-- test/jdk/java/util/zip/ZipFile/crash.jar | Bin 781 -> 0 bytes test/jdk/java/util/zip/ZipFile/input.jar | Bin 832 -> 0 bytes test/jdk/java/util/zip/ZipFile/input.zip | Bin 450 -> 0 bytes 14 files changed, 837 insertions(+), 555 deletions(-) delete mode 100644 test/jdk/java/util/zip/ZipFile/Available.java delete mode 100644 test/jdk/java/util/zip/ZipFile/CopyJar.java delete mode 100644 test/jdk/java/util/zip/ZipFile/EnumAfterClose.java create mode 100644 test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java delete mode 100644 test/jdk/java/util/zip/ZipFile/GetDirEntry.java delete mode 100644 test/jdk/java/util/zip/ZipFile/ReadAfterClose.java delete mode 100644 test/jdk/java/util/zip/ZipFile/crash.jar delete mode 100644 test/jdk/java/util/zip/ZipFile/input.jar delete mode 100644 test/jdk/java/util/zip/ZipFile/input.zip 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/Available.java b/test/jdk/java/util/zip/ZipFile/Available.java deleted file mode 100644 index 364a3b0243944..0000000000000 --- a/test/jdk/java/util/zip/ZipFile/Available.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. - * 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.util.zip.*; -import java.io.File; - -public class Available -{ - public static void main (String argv[]) throws Exception { - ZipFile zf = new ZipFile(new File(System.getProperty("test.src"), - "input.jar")); - ZipEntry e = zf.getEntry("ReleaseInflater.java"); - if (e.getSize() != zf.getInputStream(e).available()) { - throw new Exception("wrong return value of available"); - } - } -} diff --git a/test/jdk/java/util/zip/ZipFile/CopyJar.java b/test/jdk/java/util/zip/ZipFile/CopyJar.java deleted file mode 100644 index abeb1f3c46279..0000000000000 --- a/test/jdk/java/util/zip/ZipFile/CopyJar.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test 1.1 99/06/01 - @bug 4239446 - @summary Make sure the ZipEntry fields are correct. - */ - -import java.io.*; -import java.util.zip.*; - -public class CopyJar { - public static void main(String args[]) throws Exception { - try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), - "input.jar"))) { - ZipEntry ze = zf.getEntry("ReleaseInflater.java"); - ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream()); - InputStream in = zf.getInputStream(ze); - byte[] b = new byte[128]; - int n; - zos.putNextEntry(ze); - while((n = in.read(b)) != -1) { - zos.write(b, 0, n); - } - zos.close(); - } - } -} diff --git a/test/jdk/java/util/zip/ZipFile/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 8de20e7582e68655eefcbf3360315964b6b54c64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 781 zcmWIWW@Zs#-~hr!Ikq|sNPv@pg~8V~#8KDN&rSc|DFy~+h5&DN4v-2asImZ@nni#r z;F^6M{XE@VgG2Ou-9G!CIql=Et9OytTUYDcne&^246YbIcv__A<*VcAd$DvC3#Y_O zNv#Z)>CZHOq^XHN6%QAizT}yhcEvN**O{M+J{B>8U2*Kh)srqjJ3tuW3Yjo;FEB8K zq!yRxWhIs+#s+T8Yc>#>^H6)9k)`aNl0K^-&54)zI(NB9#uywtapOdt!=kSG_nVn@ zUquU)zrQ#4+^WpA&MRE?E84w2M_K&a;(L`T{F}XyIj8sSciyXIigfq1PyWJjU-N>` z4)?|{FV|`<5InU(*(!D2b8e3Ex7Qn{Zft1#`wfmIRCH3lu_ohq>nErvwjn9Bl zr{mo0(^b;8hf+cN(7xd%tbMP2b8d%MZS@=RY3& zbcqJvmGhtFx4)l#_O#2#fL~oTLZM96bC#xAt#y8;VsTt8IkMa6rq;I%9j8p|;0B{F zb$nhU)VvZfcLXDlP4ns zgAXt%1b8zti7=ohB3KFmB_dP+PZgjfg{~DjT0uz&0c?RxxK^YDg=_*S`jH*RiO>#Y Y9R^}}VhHeNWdq4F1K}1R?F@D>0F5Q`?EnA( 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 f5e6f5733170307cea67fb88a8abf64a3c901ab9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 832 zcmWIWW@Zs#-~d9E%yKmbB*4kQ!rSd8f^@?z@c|G_`_Kry;J(@bo4yW>V|zd<9+S&lc$fK zGJ##@@MQ~M1km0vAV#>1AI)1Jmj$Kfq$U=pdgi6&B$lKW>18FBB`%#5n0?4V;Q0N| znte_SuL>@=+tsMRS0mB$bDN>tn#}S^YN|V5mHfCny(CoYU8cAEyI=cv$N$eXdU0^d z66FqY!y}((Fdirg6~CaePR~2>`&sY&0}_Wf8BI%2-qy7E;og(2LBd*f2ee+SSryJ@ zd}2xg-@K)h4xMa0H&r3?VK=MF7TZ3SpBqefv;{5jo0bwNzCK?e=V8zS{_HZoXY*&S z;pqML_`*8zHF5!-7EcQJqu%*B34KzFd?$NylK7-~YgR5h%o}UeJEW zuVzPcV#nXQs&|~H>)Wc|S-m{7DbFzY*vY)F;U6#kd|`i1Kk)JX1y*sK+nieMU&hAf zZqeyM}*a{jakbx9d{ezwv@ni^wHOp&&*Eh8w^n6X4Cr zB*K82*kCCMl-N)KJoSK*9=cZKs0KwS0@wnXaIHuQ57`7zl0bGCstMPDCSXe-0p6@^ PAbXgBa6gdF2D=>qQ1}$S 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 2ca60bd4c0654b7966eb1f05403387cbd8d33c49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 450 zcmWIWW@Zs#U|`^25Xjl1X1ww-s~RH%!!ID_VGv~qN=;0O$}G^!N-RqZ4dG;9j{oat z?g7N16)X&u@>~q9fd{>q4F&c-*OqH+y&Dv?>ZrG1)yfBs0@cAbM{>)0->G>UWxnWxibX5`G$tS9xKixZ%(2I&sb{qvu%!<>5|odPiHe$m6yHW_)ja;{no7F(ykMw;-L%I z7jQ5Bw%=jiC&imGHY>xfbji(qJ7ux+xnT2_a@F}w+;KjI4}aV5FpFLAq)+^4kxojk zhS`SjK+pK4{Ok(P)6XkyZR__cX|>tgcgXp&h;q0l+vVn^-S6idZum> From af942a693bc765c8bf509118e02e74509f7f5eba Mon Sep 17 00:00:00 2001 From: Denghui Dong Date: Thu, 11 Jan 2024 07:17:28 +0000 Subject: [PATCH 076/153] 8323188: JFR: Needless RESOURCE_ARRAY when sending EventOSInformation Reviewed-by: mgronlun --- src/hotspot/share/jfr/periodic/jfrPeriodic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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(); } From 2b7fc0506ab37f1ec1e63542fb0dcd710c33ef93 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Thu, 11 Jan 2024 07:34:14 +0000 Subject: [PATCH 077/153] 8264102: JTable Keyboards Navigation differs with Test Instructions. Reviewed-by: psadhukhan, abhiscxk --- .../com/apple/laf/AquaKeyBindings.java | 4 +- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 4 +- .../swing/plaf/motif/MotifLookAndFeel.java | 4 +- .../swing/plaf/basic/BasicLookAndFeel.java | 4 +- .../swing/plaf/metal/MetalLookAndFeel.java | 4 +- .../javax/swing/plaf/synth/SynthStyle.java | 4 +- .../sun/swing/plaf/GTKKeybindings.java | 4 +- .../sun/swing/plaf/WindowsKeybindings.java | 4 +- .../plaf/windows/WindowsLookAndFeel.java | 4 +- .../swing/JTable/KeyBoardNavigation.java | 236 ++++++++++++++++++ .../KeyBoardNavigation.html | 43 ---- .../KeyBoardNavigation.java | 170 ------------- 12 files changed, 255 insertions(+), 230 deletions(-) create mode 100644 test/jdk/javax/swing/JTable/KeyBoardNavigation.java delete mode 100644 test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.html delete mode 100644 test/jdk/javax/swing/JTable/KeyBoardNavigation/KeyBoardNavigation.java 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/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/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/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/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/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()); - }); - } -} From cb1d25fcfafaa714d3f4dfd600c7dc7c936f8c5e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 11 Jan 2024 08:13:28 +0000 Subject: [PATCH 078/153] 8323330: [BACKOUT] JDK-8276809: java/awt/font/JNICheck/FreeTypeScalerJNICheck.java shows JNI warning on Windows Reviewed-by: prr, stuefe --- .../native/libawt/windows/awt_Win32GraphicsEnv.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp index 7dac7b17b1be4..6c949b564e960 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -126,15 +126,9 @@ BOOL DWMIsCompositionEnabled() { dwmIsCompositionEnabled = bRes; JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jboolean hasException; - JNU_CallStaticMethodByName(env, &hasException, + JNU_CallStaticMethodByName(env, NULL, "sun/awt/Win32GraphicsEnvironment", "dwmCompositionChanged", "(Z)V", (jboolean)bRes); - if (hasException) { - J2dTraceLn(J2D_TRACE_INFO, "Exception occurred in DWMIsCompositionEnabled"); - env->ExceptionDescribe(); - env->ExceptionClear(); - } return bRes; } From 35e9662767cc0a1dea9b5afa2a6d61a85297253c Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 11 Jan 2024 08:16:28 +0000 Subject: [PATCH 079/153] 8314515: java/util/concurrent/SynchronousQueue/Fairness.java failed with "Error: fair=false i=8 j=0" Reviewed-by: alanb --- .../concurrent/SynchronousQueue/Fairness.java | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) 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)); } } From b922f8d45951250b7c39cb179b9bc1a8a6256a9e Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 11 Jan 2024 09:00:44 +0000 Subject: [PATCH 080/153] 8319793: C2 compilation fails with "Bad graph detected in build_loop_late" after JDK-8279888 Reviewed-by: chagedorn, epeter --- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 2 +- src/hotspot/share/opto/castnode.cpp | 9 + src/hotspot/share/opto/castnode.hpp | 4 +- src/hotspot/share/opto/cfgnode.hpp | 4 +- src/hotspot/share/opto/ifnode.cpp | 105 +++++++++--- src/hotspot/share/opto/loopPredicate.cpp | 7 +- src/hotspot/share/opto/loopUnswitch.cpp | 4 +- src/hotspot/share/opto/loopnode.hpp | 2 +- src/hotspot/share/opto/loopopts.cpp | 39 +++-- src/hotspot/share/opto/memnode.cpp | 27 ++- src/hotspot/share/opto/memnode.hpp | 4 + src/hotspot/share/opto/node.hpp | 9 +- ...cessAboveRCAfterSmearingOrPredication.java | 158 ++++++++++++++++++ .../TestArrayAccessCastIIAboveRC.java | 57 +++++++ 14 files changed, 373 insertions(+), 58 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java 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/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/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/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..79ab0de83229b 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -305,7 +305,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 +330,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 +341,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 +352,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 +1485,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 +1578,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/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/node.hpp b/src/hotspot/share/opto/node.hpp index 015bf5d5c72ca..1b80458d3c36d 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1136,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/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/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java new file mode 100644 index 0000000000000..e8eb1e16a7a1d --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java @@ -0,0 +1,57 @@ +/* + * 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 access CastII to float above a range check that guards it + * @run main/othervm -Xbatch -XX:-TieredCompilation TestArrayAccessCastIIAboveRC + */ + +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) { + for (int i = 0; i < 50_000; ++i) { + test(); + } + } +} From e5aed6be7a184a86a32fa671d48e0781fab54183 Mon Sep 17 00:00:00 2001 From: Varada M Date: Thu, 11 Jan 2024 12:17:35 +0000 Subject: [PATCH 081/153] 8323276: StressDirListings.java fails on AIX Reviewed-by: jpai, dfuchs --- .../sun/net/httpserver/simpleserver/StressDirListings.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; From b8ae4a8c0985d1763ac48ba78943d8b992d7be77 Mon Sep 17 00:00:00 2001 From: Joachim Kern Date: Thu, 11 Jan 2024 13:12:32 +0000 Subject: [PATCH 082/153] 8320890: [AIX] Find a better way to mimic dl handle equality Reviewed-by: stuefe, mdoerr --- src/hotspot/os/aix/os_aix.cpp | 36 +-- src/hotspot/os/aix/os_aix.hpp | 2 - src/hotspot/os/aix/porting_aix.cpp | 278 +++++++++++++++++++++ src/hotspot/os/aix/porting_aix.hpp | 2 + src/hotspot/os/bsd/os_bsd.cpp | 22 ++ src/hotspot/os/linux/os_linux.cpp | 22 ++ src/hotspot/os/posix/os_posix.cpp | 20 +- src/hotspot/share/prims/jvmtiAgent.cpp | 43 ---- src/hotspot/share/prims/jvmtiAgent.hpp | 10 - src/hotspot/share/prims/jvmtiAgentList.cpp | 13 - src/hotspot/share/prims/jvmtiAgentList.hpp | 3 - src/hotspot/share/runtime/os.hpp | 1 + 12 files changed, 338 insertions(+), 114 deletions(-) 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/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 3a170edd697a0..65574294b4099 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -5469,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/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/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index f5346c9230753..f93328f52700b 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -1063,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 From 9fd855ed477bb0849ce5c774854844deec0f4c6b Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 11 Jan 2024 13:45:40 +0000 Subject: [PATCH 083/153] 8322971: KEM.getInstance() should check if a 3rd-party security provider is signed Reviewed-by: mullan, valeriep --- .../share/classes/javax/crypto/KEM.java | 22 +++++--- .../sun/crypto/provider/DHKEM/Compliance.java | 47 ++++------------- .../com/sun/crypto/provider/EvenKEMImpl.java | 51 +++++++++++++++++++ test/jdk/javax/crypto/KEM/RSA_KEM.java | 15 ++++-- 4 files changed, 90 insertions(+), 45 deletions(-) create mode 100644 test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java 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/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/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"; From c2e77e2f17b624e750dea8fd51bbfde99596690e Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 11 Jan 2024 15:19:48 +0000 Subject: [PATCH 084/153] 8319128: sun/security/pkcs11 tests fail on OL 7.9 aarch64 Reviewed-by: mbaesken --- test/jdk/ProblemList.txt | 1 - test/jdk/sun/security/pkcs11/PKCS11Test.java | 16 ++++++++++++++-- .../security/pkcs11/Provider/MultipleLogins.java | 15 ++++++++++----- .../security/pkcs11/Provider/MultipleLogins.sh | 1 + .../TestMutuallyExclusivePlatformPredicates.java | 2 +- test/lib/jdk/test/lib/Platform.java | 15 +++++++++++++++ 6 files changed, 41 insertions(+), 9 deletions(-) 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/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/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 From e10d14004fa25998231ab1d2611b75aea9b5c67d Mon Sep 17 00:00:00 2001 From: Sandhya Viswanathan Date: Thu, 11 Jan 2024 16:54:16 +0000 Subject: [PATCH 085/153] 8321712: C2: "failed: Multiple uses of register" in C2_MacroAssembler::vminmax_fp Co-authored-by: Volodymyr Paprotski Reviewed-by: kvn, thartmann, epeter, jbhateja --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 6 ++++-- .../vectorization/runner/BasicDoubleOpTest.java | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) 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/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"}) From b78896b9aafcb15f453eaed6e154a5461581407b Mon Sep 17 00:00:00 2001 From: Tim Prinzing Date: Thu, 11 Jan 2024 17:37:30 +0000 Subject: [PATCH 086/153] 8319571: Update jni/nullCaller/NullCallerTest.java to accept flags or mark as flagless Reviewed-by: mchung --- test/jdk/jni/nullCaller/NullCallerTest.java | 32 ++++----------------- 1 file changed, 6 insertions(+), 26 deletions(-) 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); } } From 93bedd7abae33f5d5eb909d3d216ee415ad2f8b2 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 11 Jan 2024 18:13:11 +0000 Subject: [PATCH 087/153] 8323213: Fix some javadoc broken links in ObjectReference, and other misc javadoc cleanups Reviewed-by: sspitsyn, amenkov --- .../classes/com/sun/jdi/ObjectReference.java | 18 +++++++++--------- .../classes/com/sun/jdi/VirtualMachine.java | 9 +++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java index dcada00d99b58..dbcf77d3e3928 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java @@ -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 @@ -306,7 +306,7 @@ Value invokeMethod(ThreadReference thread, Method method, * consequently, may result in application behavior under the * debugger that differs from its non-debugged behavior. * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - * -see {@link VirtualMachine#canBeModified()}. + * - see {@link VirtualMachine#canBeModified()}. */ void disableCollection(); @@ -317,7 +317,7 @@ Value invokeMethod(ThreadReference thread, Method method, * is necessary only if garbage collection was previously disabled * with {@link #disableCollection}. * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - * -see {@link VirtualMachine#canBeModified()}. + * - see {@link VirtualMachine#canBeModified()}. */ void enableCollection(); @@ -328,7 +328,7 @@ Value invokeMethod(ThreadReference thread, Method method, * @return true if this {@link ObjectReference} has been collected; * false otherwise. * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - * -see {@link VirtualMachine#canBeModified()}. + * - see {@link VirtualMachine#canBeModified()}. */ boolean isCollected(); @@ -351,7 +351,7 @@ Value invokeMethod(ThreadReference thread, Method method, * for a monitor. *

* Not all target VMs support this operation. See - * VirtualMachine#canGetMonitorInfo to determine if the + * {@link VirtualMachine#canGetMonitorInfo} to determine if the * operation is supported. * * @return a List of {@link ThreadReference} objects. The list @@ -372,7 +372,7 @@ List waitingThreads() * of ownership. *

* Not all target VMs support this operation. See - * VirtualMachine#canGetMonitorInfo to determine if the + * {@link VirtualMachine#canGetMonitorInfo} to determine if the * operation is supported. * * @return the {@link ThreadReference} which currently owns the @@ -392,7 +392,7 @@ List waitingThreads() * of ownership. *

* Not all target VMs support this operation. See - * VirtualMachine#canGetMonitorInfo to determine if the + * {@link VirtualMachine#canGetMonitorInfo} to determine if the * operation is supported. * * @see #owningThread @@ -422,12 +422,12 @@ List waitingThreads() * @param maxReferrers The maximum number of referring objects to return. * Must be non-negative. If zero, all referring * objects are returned. - * @return a of List of {@link ObjectReference} objects. If there are + * @return a List of {@link ObjectReference} objects. If there are * no objects that reference this object, a zero-length list is returned.. * @throws java.lang.UnsupportedOperationException if * the target virtual machine does not support this * operation - see - * {@link VirtualMachine#canGetInstanceInfo() canGetInstanceInfo()} + * {@link VirtualMachine#canGetInstanceInfo()} * @throws java.lang.IllegalArgumentException if maxReferrers is less * than zero. * @since 1.6 diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java b/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java index 0c7d064422959..0c4e833b613fc 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -427,7 +427,7 @@ default List allModules() { * @return a {@link StringReference} that mirrors the newly created * string in the target VM. * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - * -see {@link VirtualMachine#canBeModified()}. + * - see {@link VirtualMachine#canBeModified()}. */ StringReference mirrorOf(String value); @@ -448,7 +448,7 @@ default List allModules() { * @return the {@link java.lang.Process} object for this virtual * machine, or null if it was not launched by a {@link LaunchingConnector}. * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - * -see {@link VirtualMachine#canBeModified()}. + * - see {@link VirtualMachine#canBeModified()}. */ Process process(); @@ -678,7 +678,8 @@ default List allModules() { * Determines if the target VM supports the filtering of * class prepare events by source name. * - * see {@link ClassPrepareRequest#addSourceNameFilter}. + * @see ClassPrepareRequest#addSourceNameFilter + * * @return true if the feature is supported, * false otherwise. * From 4ea7b36447ea96d62b1ca164c34e2b2b74a16579 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 11 Jan 2024 20:59:53 +0000 Subject: [PATCH 088/153] 8322235: Split up and improve LocaleProvidersRun Reviewed-by: naoto --- .../libjava/HostLocaleProviderAdapter_md.c | 5 +- .../jdk/java/util/Locale/LocaleProviders.java | 35 ++- .../util/Locale/LocaleProvidersCalendar.java | 74 +++++ .../LocaleProvidersDateTimeFormatter.java | 46 ++++ .../util/Locale/LocaleProvidersFormat.java | 110 ++++++++ .../util/Locale/LocaleProvidersLogger.java | 49 ++++ .../java/util/Locale/LocaleProvidersRun.java | 258 ++++++++---------- .../util/Locale/LocaleProvidersTimeZone.java | 51 ++++ 8 files changed, 484 insertions(+), 144 deletions(-) create mode 100644 test/jdk/java/util/Locale/LocaleProvidersCalendar.java create mode 100644 test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java create mode 100644 test/jdk/java/util/Locale/LocaleProvidersFormat.java create mode 100644 test/jdk/java/util/Locale/LocaleProvidersLogger.java create mode 100644 test/jdk/java/util/Locale/LocaleProvidersTimeZone.java 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/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/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java new file mode 100644 index 0000000000000..e304dc73facf0 --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java @@ -0,0 +1,46 @@ +/* + * 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 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 + */ + +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/Locale/LocaleProvidersLogger.java b/test/jdk/java/util/Locale/LocaleProvidersLogger.java new file mode 100644 index 0000000000000..a6e15914c3b51 --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersLogger.java @@ -0,0 +1,49 @@ +/* + * 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 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 org.junit.jupiter.api.Test; + +public class LocaleProvidersLogger { + + /* + * 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/jdk/java/util/Locale/LocaleProvidersTimeZone.java b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java new file mode 100644 index 0000000000000..46ab5054306df --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java @@ -0,0 +1,51 @@ +/* + * 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 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 + */ + +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"); + } +} From 49e61213474b846fd081e890e5abfbbbb9b79e3c Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Thu, 11 Jan 2024 21:48:58 +0000 Subject: [PATCH 089/153] 8310813: Simplify and modernize equals, hashCode, and compareTo for BigInteger Reviewed-by: rriggs, redestad, rgiulietti --- .../share/classes/java/math/BigInteger.java | 42 ++--- test/jdk/java/math/BigInteger/HashCode.java | 74 +++++++++ .../bench/java/math/BigIntegerCompareTo.java | 89 ++++++++++ .../bench/java/math/BigIntegerEquals.java | 89 ++++++++++ .../bench/java/math/BigIntegerHashCode.java | 87 ++++++++++ .../org/openjdk/bench/java/math/Shared.java | 157 ++++++++++++++++++ 6 files changed, 511 insertions(+), 27 deletions(-) create mode 100644 test/jdk/java/math/BigInteger/HashCode.java create mode 100644 test/micro/org/openjdk/bench/java/math/BigIntegerCompareTo.java create mode 100644 test/micro/org/openjdk/bench/java/math/BigIntegerEquals.java create mode 100644 test/micro/org/openjdk/bench/java/math/BigIntegerHashCode.java create mode 100644 test/micro/org/openjdk/bench/java/math/Shared.java 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/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/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; + } +} From e4389d8dc224419b8c1ee08e9f2dea0f103c6845 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Thu, 11 Jan 2024 22:38:39 +0000 Subject: [PATCH 090/153] 8323571: Regression in source resolution process Reviewed-by: lancea, naoto --- .../internal/impl/XMLEntityManager.java | 42 ++-- .../unittest/common/catalog/NullIdTest.java | 201 ++++++++++++++++++ .../xml/jaxp/unittest/common/catalog/core.xsd | 97 +++++++++ .../jaxp/unittest/common/catalog/events.xsd | 35 +++ 4 files changed, 357 insertions(+), 18 deletions(-) create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java index 6e5663bfa2c68..f922849d5fab2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -94,7 +94,7 @@ * @author K.Venugopal SUN Microsystems * @author Neeraj Bajaj SUN Microsystems * @author Sunitha Reddy SUN Microsystems - * @LastModified: Nov 2023 + * @LastModified: Jan 2024 */ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { @@ -1038,8 +1038,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI } // Step 2: custom catalog if specified - if ((publicId != null || literalSystemId != null) && - staxInputSource == null && (fUseCatalog && fCatalogFile != null)) { + if (staxInputSource == null + && (publicId != null || literalSystemId != null) + && (fUseCatalog && fCatalogFile != null)) { if (fCatalogResolver == null) { fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve); fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures); @@ -1049,8 +1050,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI } // Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue - if ((publicId != null || literalSystemId != null) && - staxInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { + if (staxInputSource == null + && (publicId != null || literalSystemId != null) + && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { initJdkCatalogResolver(); staxInputSource = resolveWithCatalogStAX(fDefCR, JdkCatalog.JDKCATALOG, publicId, literalSystemId); @@ -1061,9 +1063,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI // Note if both publicId and systemId are null, the resolution process continues as usual if (staxInputSource != null) { fISCreatedByResolver = true; - } else if ((publicId == null && literalSystemId == null) || - (JdkXmlUtils.isResolveContinue(fCatalogFeatures) && - fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { + } else if ((publicId == null && literalSystemId == null) + || (JdkXmlUtils.isResolveContinue(fCatalogFeatures) + && fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { staxInputSource = new StaxXMLInputSource( new XMLInputSource(publicId, literalSystemId, baseSystemId, true), false); } @@ -1206,8 +1208,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th } // Step 2: custom catalog if specified - if ((publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null) - && xmlInputSource == null && (fUseCatalog && fCatalogFile != null)) { + if (xmlInputSource == null + && (publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null) + && (fUseCatalog && fCatalogFile != null)) { if (fCatalogResolver == null) { fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve); fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures); @@ -1217,8 +1220,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th } // Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue - if ((publicId != null || literalSystemId != null) - && xmlInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { + if (xmlInputSource == null + && (publicId != null || literalSystemId != null) + && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { initJdkCatalogResolver(); // unlike a custom catalog, the JDK Catalog only contains entity references xmlInputSource = resolveEntity(fDefCR, publicId, literalSystemId, baseSystemId); @@ -1226,11 +1230,13 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th // Step 4: default resolution if not resolved by a resolver and the RESOLVE // feature is set to 'continue' - // Note if both publicId and systemId are null, the resolution process continues as usual - if ((publicId == null && literalSystemId == null) || - ((xmlInputSource == null) && JdkXmlUtils.isResolveContinue(fCatalogFeatures) && - fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { - xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false); + if (xmlInputSource == null) { + // Note if both publicId and systemId are null, the resolution process continues as usual + if ((publicId == null && literalSystemId == null) || + (JdkXmlUtils.isResolveContinue(fCatalogFeatures) && + fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { + xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false); + } } return xmlInputSource; 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8e12053e0352a26ecd7f2b9bc298ddb8fb4bb61b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 11 Jan 2024 22:58:20 +0000 Subject: [PATCH 091/153] 8322799: Test JPKG003-013: ServiceTest fails because the user cannot uninstall the "servicetest" package on OEL 9.2 x64 and OEL 9.2 64-bit Arm (aarch64) Reviewed-by: almatvee --- .../classes/jdk/jpackage/internal/resources/services_utils.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh index 730137104cf4f..27a71ab616184 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh @@ -4,7 +4,8 @@ register_services () { for unit in "$@"; do - systemctl enable --now "$unit" + local unit_name=`basename "$unit"` + systemctl enable --now "$unit_name" done } From 0ff2deab5d6b8228ddfed9ae08820d2adf2330c2 Mon Sep 17 00:00:00 2001 From: Renjith Kannath Pariyangad Date: Fri, 12 Jan 2024 02:55:22 +0000 Subject: [PATCH 092/153] 8320673: PageFormat/CustomPaper.java has no Pass/Fail buttons; multiple instructions Reviewed-by: serb, aivanov --- .../awt/print/PageFormat/CustomPaper.java | 332 +++++++----------- 1 file changed, 135 insertions(+), 197 deletions(-) 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(); + } +} From 8d9814a5212bd1a339d7a2aa7a5fb4cefe2e9024 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 12 Jan 2024 06:12:20 +0000 Subject: [PATCH 093/153] 8322757: Enable -Wparentheses warnings Reviewed-by: dholmes, jwaters, erikj, ihse --- make/hotspot/lib/CompileJvm.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 \ From 82a63a03c0155288e8e43b9f766c8be70be50b6a Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 12 Jan 2024 07:53:41 +0000 Subject: [PATCH 094/153] 8258979: The image didn't show correctly with GTK LAF Reviewed-by: psadhukhan, tr --- .../javax/swing/plaf/synth/SynthTreeUI.java | 43 ++++--- .../javax/swing/JTree/8038113/bug8038113.html | 36 ------ .../javax/swing/JTree/8038113/bug8038113.java | 82 ------------ test/jdk/javax/swing/JTree/bug8038113.java | 120 ++++++++++++++++++ 4 files changed, 144 insertions(+), 137 deletions(-) delete mode 100644 test/jdk/javax/swing/JTree/8038113/bug8038113.html delete mode 100644 test/jdk/javax/swing/JTree/8038113/bug8038113.java create mode 100644 test/jdk/javax/swing/JTree/bug8038113.java 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/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; + } +} From 66520be7a752ebade6c88d164bc87c4bfcfce40a Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Fri, 12 Jan 2024 08:21:42 +0000 Subject: [PATCH 095/153] 8280056: gtest/LargePageGtests.java#use-large-pages failed "os.release_one_mapping_multi_commits_vm" Reviewed-by: stuefe, gziemski --- test/hotspot/gtest/runtime/test_os.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) 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) { From e72723dc5c61292303a992319794e5edb28a4e98 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 12 Jan 2024 08:33:27 +0000 Subject: [PATCH 096/153] 8323296: java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java#id1 timed out Reviewed-by: jpai --- .../stress/GetStackTraceALotWhenPinned.java | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) 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(); + } + } + } + + } } From 7c3a39f400d97a443be146d928f85aa850d3b5cb Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 12 Jan 2024 08:57:09 +0000 Subject: [PATCH 097/153] 8323297: Fix incorrect placement of precompiled.hpp include lines Reviewed-by: kbarrett, dholmes, shade, ysr --- .../ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp | 6 +++--- src/hotspot/cpu/ppc/gc/x/xBarrierSetAssembler_ppc.cpp | 2 +- src/hotspot/share/gc/z/zCollectedHeap.cpp | 1 - src/hotspot/share/gc/z/zVerify.cpp | 2 +- src/hotspot/share/opto/split_if.cpp | 5 ++--- 5 files changed, 7 insertions(+), 9 deletions(-) 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/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/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 6950f66915871..dafe680939e72 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,6 +36,7 @@ #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" 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) { From ba23025cd8a9c1af37afea6444ce5ea2ff41e5af Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 12 Jan 2024 09:32:50 +0000 Subject: [PATCH 098/153] 8322957: Generational ZGC: Relocation selection must join the STS Co-authored-by: Axel Boldt-Christmas Reviewed-by: eosterlund, aboldtch --- src/hotspot/share/gc/shared/workerThread.cpp | 49 +++++++++-------- src/hotspot/share/gc/shared/workerThread.hpp | 6 ++- src/hotspot/share/gc/z/zBarrier.inline.hpp | 13 +---- src/hotspot/share/gc/z/zGeneration.cpp | 6 ++- src/hotspot/share/gc/z/zGeneration.hpp | 1 + src/hotspot/share/gc/z/zIterator.inline.hpp | 10 ++++ src/hotspot/share/gc/z/zRelocate.cpp | 26 +++++++-- src/hotspot/share/gc/z/zRelocate.hpp | 7 +++ src/hotspot/share/gc/z/zRelocationSet.cpp | 7 +++ .../share/gc/z/zUncoloredRoot.inline.hpp | 3 +- src/hotspot/share/gc/z/zVerify.cpp | 53 ++++++++++++++++++- src/hotspot/share/gc/z/zVerify.hpp | 2 + src/hotspot/share/runtime/thread.cpp | 1 + src/hotspot/share/runtime/thread.hpp | 5 ++ 14 files changed, 148 insertions(+), 41 deletions(-) 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/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/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/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/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 dafe680939e72..c88d7ad7978c9 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -43,16 +43,67 @@ #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/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: From 3e19bf88d5b51fe10c183f930b99bce961a368c1 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 12 Jan 2024 10:00:37 +0000 Subject: [PATCH 099/153] 8323529: Relativize test image dependencies in microbenchmarks Reviewed-by: mcimadamore, jvernee, erikj --- make/RunTests.gmk | 5 +++++ .../bench/java/lang/foreign/CallOverheadConstant.java | 2 +- .../openjdk/bench/java/lang/foreign/CallOverheadVirtual.java | 2 +- .../org/openjdk/bench/java/lang/foreign/CriticalCalls.java | 2 +- .../openjdk/bench/java/lang/foreign/LoopOverOfAddress.java | 2 +- .../org/openjdk/bench/java/lang/foreign/PointerInvoke.java | 2 +- test/micro/org/openjdk/bench/java/lang/foreign/QSort.java | 2 +- .../org/openjdk/bench/java/lang/foreign/StrLenTest.java | 2 +- .../org/openjdk/bench/java/lang/foreign/ToCStringTest.java | 2 +- .../openjdk/bench/java/lang/foreign/ToJavaStringTest.java | 2 +- test/micro/org/openjdk/bench/java/lang/foreign/Upcalls.java | 2 +- .../bench/java/lang/foreign/pointers/PointerBench.java | 2 +- .../openjdk/bench/java/lang/foreign/points/PointsAccess.java | 2 +- .../openjdk/bench/java/lang/foreign/points/PointsAlloc.java | 2 +- .../bench/java/lang/foreign/points/PointsDistance.java | 2 +- .../openjdk/bench/java/lang/foreign/points/PointsFree.java | 2 +- .../org/openjdk/bench/java/lang/foreign/xor/XorTest.java | 2 +- 17 files changed, 21 insertions(+), 16 deletions(-) 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/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 { From ed182223655feee5356d42a94dd74950e9595724 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Fri, 12 Jan 2024 10:43:16 +0000 Subject: [PATCH 100/153] 8323190: Segfault during deoptimization of C2-compiled code Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/output.cpp | 30 ++++++++- .../escapeAnalysis/TestInvalidLocation.java | 65 +++++++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java 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/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(); + } +} From 7dc9dd6fdf500bb5156983097bc399d286407afb Mon Sep 17 00:00:00 2001 From: Lei Zaakjyu Date: Fri, 12 Jan 2024 10:56:50 +0000 Subject: [PATCH 101/153] 8234502: Merge GenCollectedHeap and SerialHeap Reviewed-by: ayang, cjplummer --- src/hotspot/share/gc/serial/generation.hpp | 2 +- src/hotspot/share/gc/serial/serialHeap.cpp | 1001 +++++++++++++++- src/hotspot/share/gc/serial/serialHeap.hpp | 304 ++++- .../share/gc/serial/serialVMOperations.cpp | 48 + .../share/gc/serial/serialVMOperations.hpp | 66 ++ .../share/gc/serial/vmStructs_serial.hpp | 7 +- .../share/gc/shared/cardTableBarrierSet.cpp | 2 +- src/hotspot/share/gc/shared/collectedHeap.hpp | 3 +- .../share/gc/shared/gcVMOperations.cpp | 24 +- .../share/gc/shared/gcVMOperations.hpp | 36 +- .../share/gc/shared/genCollectedHeap.cpp | 1035 ----------------- .../share/gc/shared/genCollectedHeap.hpp | 346 ------ src/hotspot/share/gc/shared/space.cpp | 1 - .../share/gc/shared/spaceDecorator.hpp | 4 +- src/hotspot/share/gc/shared/vmStructs_gc.hpp | 8 - .../share/classes/sun/jvm/hotspot/HSDB.java | 5 +- .../sun/jvm/hotspot/gc/serial/SerialHeap.java | 99 +- .../hotspot/gc/shared/GenCollectedHeap.java | 129 -- .../sun/jvm/hotspot/tools/HeapSummary.java | 8 +- .../jvm/hotspot/utilities/PointerFinder.java | 11 +- .../hotspot/utilities/PointerLocation.java | 5 +- 21 files changed, 1537 insertions(+), 1607 deletions(-) create mode 100644 src/hotspot/share/gc/serial/serialVMOperations.cpp create mode 100644 src/hotspot/share/gc/serial/serialVMOperations.hpp delete mode 100644 src/hotspot/share/gc/shared/genCollectedHeap.cpp delete mode 100644 src/hotspot/share/gc/shared/genCollectedHeap.hpp delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index d93c2b66df717..2f453e2ac8173 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -228,7 +228,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). diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 9361a4e5eb961..933dc12f59e1c 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -34,15 +34,75 @@ #include "memory/universe.hpp" #include "runtime/mutexLocker.hpp" #include "services/memoryManager.hpp" +#include "serialVMOperations.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/genMarkSweep.hpp" +#include "gc/serial/markSweep.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/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/weakProcessor.hpp" +#include "gc/shared/workerThread.hpp" +#include "memory/iterator.hpp" +#include "memory/metaspaceCounters.hpp" +#include "memory/metaspaceUtils.hpp" +#include "memory/resourceArea.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 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), + _full_collections_completed(0), + _young_manager(nullptr), + _old_manager(nullptr), + _eden_pool(nullptr), _survivor_pool(nullptr), _old_pool(nullptr) { @@ -133,3 +193,938 @@ 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(); +} + +// Update the _full_collections_completed counter +// at the end of a stop-world full GC. +unsigned int SerialHeap::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 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(); + 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 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..d0ed728dafb28 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -27,9 +27,17 @@ #include "gc/serial/defNewGeneration.hpp" #include "gc/serial/tenuredGeneration.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "utilities/growableArray.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; + class GCMemoryManager; class MemoryPool; class OopIterateClosure; @@ -55,7 +63,299 @@ 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; + + // 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; + +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; + + // 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; } + + // 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/serial/serialVMOperations.cpp b/src/hotspot/share/gc/serial/serialVMOperations.cpp new file mode 100644 index 0000000000000..8663dcfad2a1a --- /dev/null +++ b/src/hotspot/share/gc/serial/serialVMOperations.cpp @@ -0,0 +1,48 @@ +/* + * 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 "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..149a103ab1e86 --- /dev/null +++ b/src/hotspot/share/gc/serial/serialVMOperations.hpp @@ -0,0 +1,66 @@ +/* + * 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_SERIAL_SERIALVMOPERATIONS_HPP +#define SHARE_GC_SERIAL_SERIALVMOPERATIONS_HPP + +#include "gc/shared/gcVMOperations.hpp" +#include "gc/serial/serialHeap.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/vmStructs_serial.hpp b/src/hotspot/share/gc/serial/vmStructs_serial.hpp index c99b90aa7d66e..cc3e69133a54e 100644 --- a/src/hotspot/share/gc/serial/vmStructs_serial.hpp +++ b/src/hotspot/share/gc/serial/vmStructs_serial.hpp @@ -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/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp index b7d706df6e395..048a382f6447f 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp @@ -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..9702607fb1417 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -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..0c9e37380a580 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -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..444327e9539eb 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.hpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.hpp @@ -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 cf101caae38b3..0000000000000 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ /dev/null @@ -1,1035 +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)); -} - -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); -} - -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 1c1759f1422be..0000000000000 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ /dev/null @@ -1,346 +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); - - // 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; -}; - -#endif // SHARE_GC_SHARED_GENCOLLECTEDHEAP_HPP diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 67d3ad5338388..b4f1e47e66d82 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -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" diff --git a/src/hotspot/share/gc/shared/spaceDecorator.hpp b/src/hotspot/share/gc/shared/spaceDecorator.hpp index 14ee14352d151..13ea59c16c5b6 100644 --- a/src/hotspot/share/gc/shared/spaceDecorator.hpp +++ b/src/hotspot/share/gc/shared/spaceDecorator.hpp @@ -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 a5d671a3b9295..f219ec8d36be1 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -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 @@ -109,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) \ \ @@ -146,7 +142,6 @@ /******************************************/ \ \ declare_toplevel_type(CollectedHeap) \ - declare_type(GenCollectedHeap, CollectedHeap) \ declare_toplevel_type(Generation) \ declare_toplevel_type(Space) \ declare_type(ContiguousSpace, Space) \ @@ -175,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/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java index d54cc7fb56e27..c59bebb5d11aa 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java @@ -36,6 +36,7 @@ import sun.jvm.hotspot.gc.epsilon.*; import sun.jvm.hotspot.gc.parallel.*; import sun.jvm.hotspot.gc.shared.*; +import sun.jvm.hotspot.gc.serial.*; import sun.jvm.hotspot.gc.shenandoah.*; import sun.jvm.hotspot.gc.g1.*; import sun.jvm.hotspot.gc.x.*; @@ -1076,8 +1077,8 @@ public void addAnnotation(Address addr, OopHandle handle) { CollectedHeap collHeap = VM.getVM().getUniverse().heap(); boolean bad = true; anno = "BAD OOP"; - if (collHeap instanceof GenCollectedHeap) { - GenCollectedHeap heap = (GenCollectedHeap) collHeap; + if (collHeap instanceof SerialHeap) { + SerialHeap heap = (SerialHeap) collHeap; for (int i = 0; i < heap.nGens(); i++) { if (heap.getGen(i).isIn(handle)) { if (i == 0) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java index b26e9aa21f975..958415e5a42f2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java @@ -24,11 +24,15 @@ package sun.jvm.hotspot.gc.serial; -import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.gc.shared.GenCollectedHeap; -import sun.jvm.hotspot.gc.shared.CollectedHeapName; +import java.io.*; -public class SerialHeap extends GenCollectedHeap { +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.gc.shared.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +public class SerialHeap extends CollectedHeap { public SerialHeap(Address addr) { super(addr); @@ -37,4 +41,91 @@ public SerialHeap(Address addr) { public CollectedHeapName kind() { return CollectedHeapName.SERIAL; } + + private static AddressField youngGenField; + private static AddressField oldGenField; + + private static GenerationFactory genFactory; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("SerialHeap"); + + youngGenField = type.getAddressField("_young_gen"); + oldGenField = type.getAddressField("_old_gen"); + + genFactory = new GenerationFactory(); + } + + public int nGens() { + return 2; // Young + Old + } + + public Generation getGen(int i) { + if (Assert.ASSERTS_ENABLED) { + Assert.that((i == 0) || (i == 1), "Index " + i + + " out of range (should be 0 or 1)"); + } + + switch (i) { + case 0: + return genFactory.newObject(youngGenField.getValue(addr)); + case 1: + return genFactory.newObject(oldGenField.getValue(addr)); + default: + // no generation for i, and assertions disabled. + return null; + } + } + + public boolean isIn(Address a) { + for (int i = 0; i < nGens(); i++) { + Generation gen = getGen(i); + if (gen.isIn(a)) { + return true; + } + } + + return false; + } + + public long capacity() { + long capacity = 0; + for (int i = 0; i < nGens(); i++) { + capacity += getGen(i).capacity(); + } + return capacity; + } + + public long used() { + long used = 0; + for (int i = 0; i < nGens(); i++) { + used += getGen(i).used(); + } + return used; + } + + public void liveRegionsIterate(LiveRegionsClosure closure) { + // Run through all generations, obtaining bottom-top pairs. + for (int i = 0; i < nGens(); i++) { + Generation gen = getGen(i); + gen.liveRegionsIterate(closure); + } + } + + public void printOn(PrintStream tty) { + for (int i = 0; i < nGens(); i++) { + tty.print("Gen " + i + ": "); + getGen(i).printOn(tty); + tty.println("Invocations: " + getGen(i).invocations()); + tty.println(); + } + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java deleted file mode 100644 index 3442a0629e2f3..0000000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2000, 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. - * - */ - -package sun.jvm.hotspot.gc.shared; - -import java.io.*; -import java.util.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.gc.shared.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public abstract class GenCollectedHeap extends CollectedHeap { - private static AddressField youngGenField; - private static AddressField oldGenField; - - private static GenerationFactory genFactory; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("GenCollectedHeap"); - - youngGenField = type.getAddressField("_young_gen"); - oldGenField = type.getAddressField("_old_gen"); - - genFactory = new GenerationFactory(); - } - - public GenCollectedHeap(Address addr) { - super(addr); - } - - public int nGens() { - return 2; // Young + Old - } - - public Generation getGen(int i) { - if (Assert.ASSERTS_ENABLED) { - Assert.that((i == 0) || (i == 1), "Index " + i + - " out of range (should be 0 or 1)"); - } - - switch (i) { - case 0: - return genFactory.newObject(youngGenField.getValue(addr)); - case 1: - return genFactory.newObject(oldGenField.getValue(addr)); - default: - // no generation for i, and assertions disabled. - return null; - } - } - - public boolean isIn(Address a) { - for (int i = 0; i < nGens(); i++) { - Generation gen = getGen(i); - if (gen.isIn(a)) { - return true; - } - } - - return false; - } - - public long capacity() { - long capacity = 0; - for (int i = 0; i < nGens(); i++) { - capacity += getGen(i).capacity(); - } - return capacity; - } - - public long used() { - long used = 0; - for (int i = 0; i < nGens(); i++) { - used += getGen(i).used(); - } - return used; - } - - public void liveRegionsIterate(LiveRegionsClosure closure) { - // Run through all generations, obtaining bottom-top pairs. - for (int i = 0; i < nGens(); i++) { - Generation gen = getGen(i); - gen.liveRegionsIterate(closure); - } - } - - public void printOn(PrintStream tty) { - for (int i = 0; i < nGens(); i++) { - tty.print("Gen " + i + ": "); - getGen(i).printOn(tty); - tty.println("Invocations: " + getGen(i).invocations()); - tty.println(); - } - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index 83a820eed07f6..765a63ca58737 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -93,10 +93,10 @@ public void run() { System.out.println(); System.out.println("Heap Usage:"); - if (heap instanceof GenCollectedHeap) { - GenCollectedHeap genHeap = (GenCollectedHeap) heap; - for (int n = 0; n < genHeap.nGens(); n++) { - Generation gen = genHeap.getGen(n); + if (heap instanceof SerialHeap) { + SerialHeap sh = (SerialHeap) heap; + for (int n = 0; n < sh.nGens(); n++) { + Generation gen = sh.getGen(n); if (gen instanceof DefNewGeneration) { System.out.println("New Generation (Eden + 1 Survivor Space):"); printGen(gen); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java index e9577a2ad35bf..f8d451f0fd289 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java @@ -27,6 +27,7 @@ import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; +import sun.jvm.hotspot.gc.serial.*; import sun.jvm.hotspot.gc.shared.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.memory.*; @@ -84,12 +85,12 @@ public static PointerLocation find(Address a) { // Check if address is in the java heap. CollectedHeap heap = VM.getVM().getUniverse().heap(); - if (heap instanceof GenCollectedHeap) { - GenCollectedHeap genheap = (GenCollectedHeap) heap; - if (genheap.isIn(a)) { + if (heap instanceof SerialHeap) { + SerialHeap sh = (SerialHeap) heap; + if (sh.isIn(a)) { loc.heap = heap; - for (int i = 0; i < genheap.nGens(); i++) { - Generation g = genheap.getGen(i); + for (int i = 0; i < sh.nGens(); i++) { + Generation g = sh.getGen(i); if (g.isIn(a)) { loc.gen = g; break; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java index ee4f5f7022425..2aeb3d972007b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java @@ -28,6 +28,7 @@ import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; +import sun.jvm.hotspot.gc.serial.*; import sun.jvm.hotspot.gc.shared.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.memory.*; @@ -111,11 +112,11 @@ public boolean isInHeap() { } public boolean isInNewGen() { - return ((gen != null) && (gen.equals(((GenCollectedHeap)heap).getGen(0)))); + return ((gen != null) && (gen.equals(((SerialHeap)heap).getGen(0)))); } public boolean isInOldGen() { - return ((gen != null) && (gen.equals(((GenCollectedHeap)heap).getGen(1)))); + return ((gen != null) && (gen.equals(((SerialHeap)heap).getGen(1)))); } public boolean inOtherGen() { From 68c4286026bc2c0ec0f594e0b96fe03fe5624d6d Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 12 Jan 2024 12:29:07 +0000 Subject: [PATCH 102/153] 8323008: filter out harmful -std* flags added by autoconf from CXX Reviewed-by: erikj, clanger, ihse --- make/autoconf/toolchain.m4 | 6 +++++- make/autoconf/util.m4 | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) 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 ]) From be900f1253fe130347385f0daec772c20a79ed57 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 12 Jan 2024 13:12:37 +0000 Subject: [PATCH 103/153] 8323425: JFR: Auto-generated filename doesn't work with time-limited recording Reviewed-by: mgronlun --- .../jdk/jfr/internal/PlatformRecording.java | 61 +++++++++++----- .../jdk/jfr/internal/ShutdownHook.java | 27 +------ .../jdk/jfr/internal/dcmd/DCmdStart.java | 9 ++- .../jcmd/TestJcmdStartGeneratedFilename.java | 70 +++++++++++++++++++ 4 files changed, 122 insertions(+), 45 deletions(-) create mode 100644 test/jdk/jdk/jfr/jcmd/TestJcmdStartGeneratedFilename.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index e7b2282cc678b..6014bbbf9d251 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, 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 @@ -38,6 +38,8 @@ import java.nio.file.StandardOpenOption; import java.security.AccessControlContext; import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; @@ -76,7 +78,7 @@ public final class PlatformRecording implements AutoCloseable { private boolean toDisk = true; private String name; private boolean dumpOnExit; - private SafePath dumpOnExitDirectory = new SafePath("."); + private SafePath dumpDirectory; // Timestamp information private Instant stopTime; private Instant startTime; @@ -89,7 +91,7 @@ public final class PlatformRecording implements AutoCloseable { private TimerTask stopTask; private TimerTask startTask; @SuppressWarnings("removal") - private AccessControlContext noDestinationDumpOnExitAccessControlContext; + private final AccessControlContext dumpDirectoryControlContext; private boolean shouldWriteActiveRecordingEvent = true; private Duration flushInterval = Duration.ofSeconds(1); private long finalStartChunkNanos = Long.MIN_VALUE; @@ -99,11 +101,11 @@ public final class PlatformRecording implements AutoCloseable { PlatformRecording(PlatformRecorder recorder, long id) { // Typically the access control context is taken // when you call dump(Path) or setDestination(Path), - // but if no destination is set and dumpOnExit=true + // but if no destination is set and the filename is auto-generated, // the control context of the recording is taken when the // Recording object is constructed. This works well for // -XX:StartFlightRecording and JFR.dump - this.noDestinationDumpOnExitAccessControlContext = AccessController.getContext(); + this.dumpDirectoryControlContext = AccessController.getContext(); this.id = id; this.recorder = recorder; this.name = String.valueOf(id); @@ -174,7 +176,9 @@ public boolean stop(String reason) { newState = getState(); } WriteableUserPath dest = getDestination(); - + if (dest == null && dumpDirectory != null) { + dest = makeDumpPath(); + } if (dest != null) { try { dumpStopped(dest); @@ -191,6 +195,33 @@ public boolean stop(String reason) { return true; } + @SuppressWarnings("removal") + public WriteableUserPath makeDumpPath() { + try { + String name = JVMSupport.makeFilename(getRecording()); + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public WriteableUserPath run() throws Exception { + SafePath p = dumpDirectory; + if (p == null) { + p = new SafePath("."); + } + return new WriteableUserPath(p.toPath().resolve(name)); + } + }, dumpDirectoryControlContext); + } catch (PrivilegedActionException e) { + Throwable t = e.getCause(); + if (t instanceof SecurityException) { + Logger.log(LogTag.JFR, LogLevel.WARN, "Not allowed to create dump path for recording " + recording.getId() + " on exit."); + } + if (t instanceof IOException) { + Logger.log(LogTag.JFR, LogLevel.WARN, "Could not dump " + recording.getId() + " on exit."); + } + return null; + } + } + + public void scheduleStart(Duration delay) { synchronized (recorder) { ensureOkForSchedule(); @@ -697,11 +728,6 @@ void clearDestination() { destination = null; } - @SuppressWarnings("removal") - public AccessControlContext getNoDestinationDumpOnExitAccessControlContext() { - return noDestinationDumpOnExitAccessControlContext; - } - void setShouldWriteActiveRecordingEvent(boolean shouldWrite) { this.shouldWriteActiveRecordingEvent = shouldWrite; } @@ -828,12 +854,13 @@ private static List reduceFromEnd(Long maxSize, List + * Only to be used by DCmdStart. + */ + public void setDumpDirectory(SafePath directory) { + this.dumpDirectory = directory; } public void setFlushInterval(Duration interval) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java index 2eabf74404cf7..afd9ec09bd9f1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, 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 @@ -65,7 +65,7 @@ private void dump(PlatformRecording recording) { try { WriteableUserPath dest = recording.getDestination(); if (dest == null) { - dest = makeDumpOnExitPath(recording); + dest = recording.makeDumpPath(); recording.setDestination(dest); } if (dest != null) { @@ -78,29 +78,6 @@ private void dump(PlatformRecording recording) { } } - @SuppressWarnings("removal") - private WriteableUserPath makeDumpOnExitPath(PlatformRecording recording) { - try { - String name = JVMSupport.makeFilename(recording.getRecording()); - AccessControlContext acc = recording.getNoDestinationDumpOnExitAccessControlContext(); - return AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public WriteableUserPath run() throws Exception { - return new WriteableUserPath(recording.getDumpOnExitDirectory().toPath().resolve(name)); - } - }, acc); - } catch (PrivilegedActionException e) { - Throwable t = e.getCause(); - if (t instanceof SecurityException) { - Logger.log(LogTag.JFR, LogLevel.WARN, "Not allowed to create dump path for recording " + recording.getId() + " on exit."); - } - if (t instanceof IOException) { - Logger.log(LogTag.JFR, LogLevel.WARN, "Could not dump " + recording.getId() + " on exit."); - } - return null; - } - } - static final class ExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java index aa7165cb9754c..a7e423e549aa9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.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 @@ -29,6 +29,8 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.AccessControlContext; +import java.security.AccessController; import java.text.ParseException; import java.time.Duration; import java.util.HashSet; @@ -165,11 +167,12 @@ public void execute(ArgumentParser parser) throws DCmdException { dumpOnExit = Boolean.TRUE; } Path p = Paths.get(path); - if (Files.isDirectory(p) && Boolean.TRUE.equals(dumpOnExit)) { + if (Files.isDirectory(p)) { // Decide destination filename at dump time // Purposely avoid generating filename in Recording#setDestination due to // security concerns - PrivateAccess.getInstance().getPlatformRecording(recording).setDumpOnExitDirectory(new SafePath(p)); + PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording); + pr.setDumpDirectory(new SafePath(p)); } else { safePath = resolvePath(recording, path); recording.setDestination(safePath.toPath()); 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"); + } +} From e22ab10991d9e82aad56cbfa89d5b82fd48fc8c3 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 12 Jan 2024 13:51:29 +0000 Subject: [PATCH 104/153] 8322537: Parallel: Remove experimental adjustment in PSAdaptiveSizePolicy Reviewed-by: kbarrett, tschatzl --- .../gc/parallel/psAdaptiveSizePolicy.cpp | 28 ------------------- .../share/gc/shared/adaptiveSizePolicy.hpp | 6 ---- 2 files changed, 34 deletions(-) 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/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, From 65a0672791f868556776fc435b37319ed69f7c84 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 12 Jan 2024 14:34:42 +0000 Subject: [PATCH 105/153] 8319773: Avoid inflating monitors when installing hash codes for LM_LIGHTWEIGHT Reviewed-by: rkennke, dcubed, thartmann --- src/hotspot/cpu/x86/sharedRuntime_x86.cpp | 14 ++++- src/hotspot/share/opto/library_call.cpp | 18 ++++-- src/hotspot/share/runtime/synchronizer.cpp | 61 ++++++++----------- .../whitebox/TestWBDeflateIdleMonitors.java | 7 +-- 4 files changed, 53 insertions(+), 47 deletions(-) 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/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/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/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."); } From c5e72450966ad50d57a8d22e9d634bfcb319aee9 Mon Sep 17 00:00:00 2001 From: Denghui Dong Date: Fri, 12 Jan 2024 15:21:37 +0000 Subject: [PATCH 106/153] 8322735: C2: minor improvements of bubble sort used in SuperWord::packset_sort Reviewed-by: epeter, kvn --- src/hotspot/share/opto/superword.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 4b1d9e5457291..b1d1169f3571c 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -3428,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) { From e33031b850dfd2daacb5ccf2bda265edec3ffe50 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 12 Jan 2024 17:04:51 +0000 Subject: [PATCH 107/153] 8323629: Shenandoah: Fix missing include and declaration Reviewed-by: ysr, kdnilsen, phh --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 20 ++++++++++++++----- .../share/gc/shenandoah/shenandoahPacer.hpp | 1 + .../gc/shenandoah/shenandoahTaskqueue.hpp | 2 ++ 3 files changed, 18 insertions(+), 5 deletions(-) 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/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 { From 8b6293f6bfb7b7628c6604e6c44401fc96d85cf4 Mon Sep 17 00:00:00 2001 From: Rajat Mahajan Date: Fri, 12 Jan 2024 17:14:16 +0000 Subject: [PATCH 108/153] 8301994: Remove unused code from awt_List.cpp Reviewed-by: serb, prr, aivanov --- .../windows/native/libawt/windows/awt_List.cpp | 11 ----------- 1 file changed, 11 deletions(-) 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 From 999e556be4302de4b6911e6d62ee5ca556a76469 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 12 Jan 2024 17:56:16 +0000 Subject: [PATCH 109/153] 8312518: [macos13] setFullScreenWindow() shows black screen on macOS 13 & above Reviewed-by: serb, tr, azvegint --- .../native/libawt_lwawt/awt/AWTWindow.m | 3 +- .../awt/FullScreen/SetFullScreenTest.java | 89 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/awt/FullScreen/SetFullScreenTest.java 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/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(); + } + } + } +} From 95a91682c36992c7fffae5e778d70a1df6269d3b Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 12 Jan 2024 18:57:36 +0000 Subject: [PATCH 110/153] 8323627: Shenandoah: Refactor init logger Reviewed-by: ysr, kdnilsen, shade, phh --- .../gc/shenandoah/shenandoahInitLogger.cpp | 42 +++++++------------ .../gc/shenandoah/shenandoahInitLogger.hpp | 3 +- 2 files changed, 18 insertions(+), 27 deletions(-) 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(); From c54bca6f7f5a7e4f47e804608e7ea370dcc32897 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 12 Jan 2024 19:21:52 +0000 Subject: [PATCH 111/153] 8323617: Add missing null checks to GetMousePositionWithPopup.java test Reviewed-by: serb, aivanov, dnguyen --- .../GetMousePositionWithPopup.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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(); + } }); } } From 9e9c05f0eee7c3ecc750c212e6fe5edddb8c6ed8 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 12 Jan 2024 19:40:55 +0000 Subject: [PATCH 112/153] 8322979: Add informative discussion to Modifier Reviewed-by: alanb --- .../classes/java/lang/reflect/Modifier.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) 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} From 84cf4cb350331aac147fdf4c6d130cdf5448c987 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Fri, 12 Jan 2024 20:41:49 +0000 Subject: [PATCH 113/153] 8318563: GetClassFields should not use random access to field Reviewed-by: sspitsyn, cjplummer, fparain --- src/hotspot/share/prims/jvmtiEnv.cpp | 26 ++++++-------- src/hotspot/share/runtime/reflectionUtils.hpp | 35 ++++++++++++++++++- 2 files changed, 44 insertions(+), 17 deletions(-) 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/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 From dc7d3b182d226253ca246dd854c85c4dd964f10e Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Fri, 12 Jan 2024 22:16:09 +0000 Subject: [PATCH 114/153] 8321489: Update LCMS to 2.16 Reviewed-by: serb, dnguyen, prr --- src/java.desktop/share/legal/lcms.md | 39 +- .../share/native/liblcms/cmsalpha.c | 26 +- .../share/native/liblcms/cmscgats.c | 487 ++++++++++++++---- .../share/native/liblcms/cmscnvrt.c | 41 +- .../share/native/liblcms/cmserr.c | 7 +- .../share/native/liblcms/cmsgamma.c | 28 +- .../share/native/liblcms/cmsgmt.c | 4 +- .../share/native/liblcms/cmsio0.c | 27 +- .../share/native/liblcms/cmsio1.c | 12 +- .../share/native/liblcms/cmslut.c | 11 +- .../share/native/liblcms/cmsnamed.c | 250 ++++++++- .../share/native/liblcms/cmsopt.c | 14 +- .../share/native/liblcms/cmspack.c | 185 ++++++- .../share/native/liblcms/cmsplugin.c | 21 +- .../share/native/liblcms/cmsps2.c | 187 +++---- .../share/native/liblcms/cmssamp.c | 2 +- .../share/native/liblcms/cmstypes.c | 271 +++++++++- .../share/native/liblcms/cmsvirt.c | 137 ++++- .../share/native/liblcms/cmsxform.c | 15 +- src/java.desktop/share/native/liblcms/lcms2.h | 53 +- .../share/native/liblcms/lcms2_internal.h | 7 +- 21 files changed, 1465 insertions(+), 359 deletions(-) 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/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;

From 5cf7947ccd1fc56e8944c28145a9c8e71f5e1a03 Mon Sep 17 00:00:00 2001
From: Sergey Bylokhov 
Date: Fri, 12 Jan 2024 23:50:28 +0000
Subject: [PATCH 115/153] 8323562: SaslInputStream.read() may return wrong
 value

Co-authored-by: Aleksey Shipilev 
Reviewed-by: shade, dfuchs
---
 .../share/classes/com/sun/jndi/ldap/sasl/SaslInputStream.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/SaslInputStream.java b/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/SaslInputStream.java
index f0746c103bc25..534f7dac766e3 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/SaslInputStream.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/SaslInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2003, 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
@@ -78,7 +78,7 @@ public int read() throws IOException {
         byte[] inBuf = new byte[1];
         int count = read(inBuf, 0, 1);
         if (count > 0) {
-            return inBuf[0];
+            return inBuf[0] & 0xff;
         } else {
             return -1;
         }

From d83ea9208577ff14b505db0bd9f7a14388ae3f1c Mon Sep 17 00:00:00 2001
From: Varada M 
Date: Sat, 13 Jan 2024 14:12:44 +0000
Subject: [PATCH 116/153] 8301466: [AIX] Revisit CommittedVirtualMemoryTest

Reviewed-by: mdoerr
---
 test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

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) {

From 71d9a83dece7eb4bdb6ffdd9caf14a1348045ce0 Mon Sep 17 00:00:00 2001
From: David Holmes 
Date: Sun, 14 Jan 2024 22:01:44 +0000
Subject: [PATCH 117/153] 8323243: JNI invocation of an abstract instance
 method corrupts the stack

Reviewed-by: coleenp, shade
---
 src/hotspot/share/prims/jni.cpp               |  5 ++
 .../abstractMethod/AbstractMethodClass.jasm   | 43 ++++++++++++
 .../abstractMethod/TestJNIAbstractMethod.java | 68 +++++++++++++++++++
 .../jni/abstractMethod/libJNIAbstractMethod.c | 43 ++++++++++++
 4 files changed, 159 insertions(+)
 create mode 100644 test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm
 create mode 100644 test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java
 create mode 100644 test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c

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/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm
new file mode 100644
index 0000000000000..24c53f2032da9
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm
@@ -0,0 +1,43 @@
+/*
+ * 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 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;
+    }
+
+    public abstract Method "abstractM":"()V";
+
+}
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/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c
new file mode 100644
index 0000000000000..35a28f7029ac3
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c
@@ -0,0 +1,43 @@
+/*
+ * 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 
+#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);
+  }
+
+  printf("Invoking abstract method ...\n");
+  (*env)->CallVoidMethod(env, receiver, mid);  // Should raise exception
+
+}

From bdee968e3e969784df130c75a5cf6a1d2847bd29 Mon Sep 17 00:00:00 2001
From: Sergey Bylokhov 
Date: Sun, 14 Jan 2024 23:05:47 +0000
Subject: [PATCH 118/153] 4760025: sRGB conversions to and from CIE XYZ
 incorrect

Reviewed-by: prr, aivanov
---
 .../SimpleSRGBToFromCIEXYZ.java               | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java

diff --git a/test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java b/test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java
new file mode 100644
index 0000000000000..c67f52263c0f3
--- /dev/null
+++ b/test/jdk/java/awt/color/ICC_ColorSpace/SimpleSRGBToFromCIEXYZ.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ * 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.ColorSpace;
+import java.util.Arrays;
+
+/**
+ * @test
+ * @bug 4760025
+ * @summary Verifies sRGB conversions to and from CIE XYZ
+ */
+public final class SimpleSRGBToFromCIEXYZ {
+
+    public static void main(String[] args) {
+        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+        for (float g : new float[]{1.0f, 0.8f, 0.6f}) {
+            float[] rgb = {0, g, 0};
+            float[] xyz = cs.toCIEXYZ(rgb);
+            float[] inv = cs.fromCIEXYZ(xyz);
+
+            if (inv[0] != 0 || Math.abs(inv[1] - g) > 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");
+            }
+        }
+    }
+}

From 1515bd7c9d70e3d6153fc82cd7db0502a15427aa Mon Sep 17 00:00:00 2001
From: Zhiqiang Zang 
Date: Mon, 15 Jan 2024 06:48:00 +0000
Subject: [PATCH 119/153] 8322077: Add Ideal transformation: (~a) | (~b) => ~(a
 & b)

Reviewed-by: thartmann, epeter
---
 src/hotspot/share/opto/addnode.cpp            |  15 +++
 .../c2/irTests/DeMorganLawIntTests.java       | 109 ++++++++++++++++++
 .../c2/irTests/DeMorganLawLongTests.java      | 109 ++++++++++++++++++
 .../c2/irTests/OrINodeIdealizationTests.java  |  68 +++++++++++
 .../c2/irTests/OrLNodeIdealizationTests.java  |  68 +++++++++++
 5 files changed, 369 insertions(+)
 create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawIntTests.java
 create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/DeMorganLawLongTests.java
 create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/OrINodeIdealizationTests.java
 create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/OrLNodeIdealizationTests.java

diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp
index 49d17d84fc91c..1b92193300449 100644
--- a/src/hotspot/share/opto/addnode.cpp
+++ b/src/hotspot/share/opto/addnode.cpp
@@ -806,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;
 }
 
@@ -872,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/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);
+    }
+}

From 922f8e44eed74b79a76a3628ebd0bca144e28091 Mon Sep 17 00:00:00 2001
From: Lei Zaakjyu 
Date: Mon, 15 Jan 2024 07:40:49 +0000
Subject: [PATCH 120/153] 8323693: Update some copyright announcements in the
 new files created in 8234502

Reviewed-by: cjplummer, dholmes
---
 src/hotspot/share/gc/serial/generation.hpp                      | 2 +-
 src/hotspot/share/gc/serial/serialHeap.cpp                      | 2 +-
 src/hotspot/share/gc/serial/serialHeap.hpp                      | 2 +-
 src/hotspot/share/gc/serial/serialVMOperations.cpp              | 2 +-
 src/hotspot/share/gc/serial/serialVMOperations.hpp              | 2 +-
 src/hotspot/share/gc/serial/vmStructs_serial.hpp                | 2 +-
 src/hotspot/share/gc/shared/cardTableBarrierSet.cpp             | 2 +-
 src/hotspot/share/gc/shared/collectedHeap.hpp                   | 2 +-
 src/hotspot/share/gc/shared/gcVMOperations.cpp                  | 2 +-
 src/hotspot/share/gc/shared/gcVMOperations.hpp                  | 2 +-
 src/hotspot/share/gc/shared/space.cpp                           | 2 +-
 src/hotspot/share/gc/shared/spaceDecorator.hpp                  | 2 +-
 src/hotspot/share/gc/shared/vmStructs_gc.hpp                    | 2 +-
 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java   | 2 +-
 .../share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java     | 2 +-
 .../share/classes/sun/jvm/hotspot/tools/HeapSummary.java        | 2 +-
 .../share/classes/sun/jvm/hotspot/utilities/PointerFinder.java  | 2 +-
 .../classes/sun/jvm/hotspot/utilities/PointerLocation.java      | 2 +-
 18 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp
index 2f453e2ac8173..9b956c9df61e8 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
diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp
index 933dc12f59e1c..cec748140e54f 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
diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp
index d0ed728dafb28..50861c2e30b9f 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
diff --git a/src/hotspot/share/gc/serial/serialVMOperations.cpp b/src/hotspot/share/gc/serial/serialVMOperations.cpp
index 8663dcfad2a1a..9e88fa5971196 100644
--- a/src/hotspot/share/gc/serial/serialVMOperations.cpp
+++ b/src/hotspot/share/gc/serial/serialVMOperations.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2023, 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
diff --git a/src/hotspot/share/gc/serial/serialVMOperations.hpp b/src/hotspot/share/gc/serial/serialVMOperations.hpp
index 149a103ab1e86..dc6ee4475c7c4 100644
--- a/src/hotspot/share/gc/serial/serialVMOperations.hpp
+++ b/src/hotspot/share/gc/serial/serialVMOperations.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2023, 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
diff --git a/src/hotspot/share/gc/serial/vmStructs_serial.hpp b/src/hotspot/share/gc/serial/vmStructs_serial.hpp
index cc3e69133a54e..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
diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp
index 048a382f6447f..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
diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp
index 9702607fb1417..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
diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp
index 0c9e37380a580..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
diff --git a/src/hotspot/share/gc/shared/gcVMOperations.hpp b/src/hotspot/share/gc/shared/gcVMOperations.hpp
index 444327e9539eb..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
diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp
index b4f1e47e66d82..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
diff --git a/src/hotspot/share/gc/shared/spaceDecorator.hpp b/src/hotspot/share/gc/shared/spaceDecorator.hpp
index 13ea59c16c5b6..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
diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp
index f219ec8d36be1..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
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
index c59bebb5d11aa..2e1d35a96fb82 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.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
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java
index 958415e5a42f2..5611a58c7b218 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/SerialHeap.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
+ * Copyright (c) 2017, 2024, 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
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java
index 765a63ca58737..3cb3859652058 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.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
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java
index f8d451f0fd289..99b45fad1a6e8 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java
@@ -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
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java
index 2aeb3d972007b..0048b8a8ac4bb 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java
@@ -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

From ba3c3bbd879eaf7532663663d73e21fafc65b574 Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev 
Date: Mon, 15 Jan 2024 09:10:11 +0000
Subject: [PATCH 121/153] 8323519: Add applications/ctw/modules to Hotspot
 tiered testing

Reviewed-by: xliu, kvn
---
 test/hotspot/jtreg/TEST.groups | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups
index 27956797948ed..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/ \

From e66a76f52410d8a4d6aadbd424679409650da9ae Mon Sep 17 00:00:00 2001
From: Lei Zaakjyu 
Date: Mon, 15 Jan 2024 09:13:47 +0000
Subject: [PATCH 122/153] 8323660: Serial: Fix header ordering and indentation

Reviewed-by: ayang, cjplummer, kbarrett
---
 src/hotspot/share/gc/serial/serialHeap.cpp    | 69 +++++++++----------
 src/hotspot/share/gc/serial/serialHeap.hpp    |  5 +-
 .../share/gc/serial/serialVMOperations.hpp    |  2 +-
 .../share/classes/sun/jvm/hotspot/HSDB.java   |  2 +-
 4 files changed, 36 insertions(+), 42 deletions(-)

diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp
index cec748140e54f..d2ac376773d29 100644
--- a/src/hotspot/share/gc/serial/serialHeap.cpp
+++ b/src/hotspot/share/gc/serial/serialHeap.cpp
@@ -23,19 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/serial/defNewGeneration.inline.hpp"
-#include "gc/serial/serialHeap.hpp"
-#include "gc/serial/tenuredGeneration.inline.hpp"
-#include "gc/shared/gcLocker.inline.hpp"
-#include "gc/shared/genMemoryPools.hpp"
-#include "gc/shared/scavengableNMethods.hpp"
-#include "gc/shared/strongRootsScope.hpp"
-#include "gc/shared/suspendibleThreadSet.hpp"
-#include "memory/universe.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "services/memoryManager.hpp"
-#include "serialVMOperations.hpp"
-
 #include "classfile/classLoaderDataGraph.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
@@ -44,8 +31,12 @@
 #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/serialVMOperations.hpp"
+#include "gc/serial/tenuredGeneration.inline.hpp"
 #include "gc/shared/cardTableBarrierSet.hpp"
 #include "gc/shared/classUnloadingContext.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -53,29 +44,36 @@
 #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/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/genMemoryPools.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"
@@ -102,7 +100,6 @@ SerialHeap::SerialHeap() :
     _full_collections_completed(0),
     _young_manager(nullptr),
     _old_manager(nullptr),
-
     _eden_pool(nullptr),
     _survivor_pool(nullptr),
     _old_pool(nullptr) {
@@ -111,7 +108,6 @@ SerialHeap::SerialHeap() :
 }
 
 void SerialHeap::initialize_serviceability() {
-
   DefNewGeneration* young = young_gen();
 
   // Add a memory pool for each space and young gen doesn't
@@ -135,7 +131,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() {
@@ -331,7 +326,7 @@ bool SerialHeap::should_try_older_generation_allocation(size_t word_size) const
          || incremental_collection_failed();
 }
 
-HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool   is_tlab) {
+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);
@@ -346,7 +341,7 @@ HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool   is_tlab) {
 }
 
 HeapWord* SerialHeap::mem_allocate_work(size_t size,
-                                              bool is_tlab) {
+                                        bool is_tlab) {
 
   HeapWord* result = nullptr;
 
@@ -443,8 +438,8 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size,
 }
 
 HeapWord* SerialHeap::attempt_allocation(size_t size,
-                                               bool is_tlab,
-                                               bool first_only) {
+                                         bool is_tlab,
+                                         bool first_only) {
   HeapWord* res = nullptr;
 
   if (_young_gen->should_allocate(size, is_tlab)) {
@@ -462,7 +457,7 @@ HeapWord* SerialHeap::attempt_allocation(size_t size,
 }
 
 HeapWord* SerialHeap::mem_allocate(size_t size,
-                                         bool* gc_overhead_limit_was_exceeded) {
+                                   bool* gc_overhead_limit_was_exceeded) {
   return mem_allocate_work(size,
                            false /* is_tlab */);
 }
@@ -473,7 +468,7 @@ bool SerialHeap::must_clear_all_soft_refs() {
 }
 
 void SerialHeap::collect_generation(Generation* gen, bool full, size_t size,
-                                          bool is_tlab, bool run_verification, bool clear_soft_refs) {
+                                    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());
@@ -512,11 +507,11 @@ void SerialHeap::collect_generation(Generation* gen, bool full, size_t size,
   }
 }
 
-void SerialHeap::do_collection(bool           full,
-                                     bool           clear_all_soft_refs,
-                                     size_t         size,
-                                     bool           is_tlab,
-                                     GenerationType max_generation) {
+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();)
 
@@ -666,7 +661,7 @@ void SerialHeap::do_collection(bool           full,
 }
 
 bool SerialHeap::should_do_full_collection(size_t size, bool full, bool is_tlab,
-                                                 SerialHeap::GenerationType max_gen) const {
+                                           SerialHeap::GenerationType max_gen) const {
   return max_gen == OldGen && _old_gen->should_collect(full, size, is_tlab);
 }
 
@@ -778,10 +773,10 @@ 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) {
+                               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");
 
@@ -847,7 +842,7 @@ void SerialHeap::collect(GCCause::Cause cause) {
 
   while (true) {
     VM_GenCollectFull op(gc_count_before, full_gc_count_before,
-                        cause, max_generation);
+                         cause, max_generation);
     VMThread::execute(&op);
 
     if (!GCCause::is_explicit_full_gc(cause)) {
@@ -874,7 +869,7 @@ void SerialHeap::do_full_collection(bool clear_all_soft_refs) {
 }
 
 void SerialHeap::do_full_collection(bool clear_all_soft_refs,
-                                          GenerationType last_generation) {
+                                    GenerationType last_generation) {
   do_collection(true,                   // full
                 clear_all_soft_refs,    // clear_all_soft_refs
                 0,                      // size
@@ -967,8 +962,8 @@ size_t SerialHeap::unsafe_max_tlab_alloc(Thread* thr) const {
 }
 
 HeapWord* SerialHeap::allocate_new_tlab(size_t min_size,
-                                              size_t requested_size,
-                                              size_t* actual_size) {
+                                        size_t requested_size,
+                                        size_t* actual_size) {
   HeapWord* result = mem_allocate_work(requested_size /* size */,
                                        true /* is_tlab */);
   if (result != nullptr) {
@@ -983,7 +978,7 @@ void SerialHeap::prepare_for_verify() {
 }
 
 void SerialHeap::generation_iterate(GenClosure* cl,
-                                          bool old_to_young) {
+                                    bool old_to_young) {
   if (old_to_young) {
     cl->do_generation(_old_gen);
     cl->do_generation(_young_gen);
diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp
index 50861c2e30b9f..77ba07b32fc6d 100644
--- a/src/hotspot/share/gc/serial/serialHeap.hpp
+++ b/src/hotspot/share/gc/serial/serialHeap.hpp
@@ -26,14 +26,13 @@
 #define SHARE_GC_SERIAL_SERIALHEAP_HPP
 
 #include "gc/serial/defNewGeneration.hpp"
-#include "gc/serial/tenuredGeneration.hpp"
-#include "utilities/growableArray.hpp"
-
 #include "gc/serial/generation.hpp"
+#include "gc/serial/tenuredGeneration.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;
diff --git a/src/hotspot/share/gc/serial/serialVMOperations.hpp b/src/hotspot/share/gc/serial/serialVMOperations.hpp
index dc6ee4475c7c4..a056740dd8549 100644
--- a/src/hotspot/share/gc/serial/serialVMOperations.hpp
+++ b/src/hotspot/share/gc/serial/serialVMOperations.hpp
@@ -25,8 +25,8 @@
 #ifndef SHARE_GC_SERIAL_SERIALVMOPERATIONS_HPP
 #define SHARE_GC_SERIAL_SERIALVMOPERATIONS_HPP
 
-#include "gc/shared/gcVMOperations.hpp"
 #include "gc/serial/serialHeap.hpp"
+#include "gc/shared/gcVMOperations.hpp"
 
 class VM_GenCollectForAllocation : public VM_CollectForAllocation {
  private:
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
index 2e1d35a96fb82..162de7c65bb36 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
@@ -35,8 +35,8 @@
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.gc.epsilon.*;
 import sun.jvm.hotspot.gc.parallel.*;
-import sun.jvm.hotspot.gc.shared.*;
 import sun.jvm.hotspot.gc.serial.*;
+import sun.jvm.hotspot.gc.shared.*;
 import sun.jvm.hotspot.gc.shenandoah.*;
 import sun.jvm.hotspot.gc.g1.*;
 import sun.jvm.hotspot.gc.x.*;

From 8643cc21333c6b51242ed3b9295b25f372244755 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Mon, 15 Jan 2024 09:35:50 +0000
Subject: [PATCH 123/153] 8323610: G1: HeapRegion pin count should be size_t to
 avoid overflows

Reviewed-by: kbarrett, ayang
---
 src/hotspot/share/gc/g1/g1YoungCollector.cpp  | 4 ++--
 src/hotspot/share/gc/g1/heapRegion.cpp        | 4 ++--
 src/hotspot/share/gc/g1/heapRegion.hpp        | 6 +++---
 src/hotspot/share/gc/g1/heapRegion.inline.hpp | 6 +++---
 src/hotspot/share/gc/g1/vmStructs_g1.hpp      | 4 ++--
 5 files changed, 12 insertions(+), 12 deletions(-)

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)   \
                                                                               \

From 45c65e6b1ac06aa06757393f1752661252e6f827 Mon Sep 17 00:00:00 2001
From: Emanuel Peter 
Date: Mon, 15 Jan 2024 10:41:05 +0000
Subject: [PATCH 124/153] 8323577: C2 SuperWord: remove AlignVector
 restrictions on IR tests added in JDK-8305055

Reviewed-by: rcastanedalo, chagedorn
---
 .../compiler/c2/irTests/TestVectorizeTypeConversion.java | 5 +----
 .../vectorization/runner/ArrayTypeConvertTest.java       | 9 ---------
 2 files changed, 1 insertion(+), 13 deletions(-)

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/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];

From cd0fe377417be65dbf1338d8b47da8817985c7d8 Mon Sep 17 00:00:00 2001
From: Emanuel Peter 
Date: Mon, 15 Jan 2024 10:44:01 +0000
Subject: [PATCH 125/153] 8323641: Test
 compiler/loopopts/superword/TestAlignVectorFuzzer.java timed out

Reviewed-by: chagedorn, kvn
---
 .../superword/TestAlignVectorFuzzer.java      | 34 ++++++++++---------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java
index 478cfbcb2c522..e27feb36e868c 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java
@@ -556,23 +556,25 @@ public static void main(String[] args) {
         tests.put("testUU_unsafe_BasIH", () -> { return testUU_unsafe_BasIH(aB.clone(), bB.clone(), cB.clone()); });
 
 
-        // Only run for 90% of the time, and subtract some margin. This ensures the shutdown has sufficient time,
+        // Only run for 40% of the time, and subtract some margin. This ensures the shutdown has sufficient time,
         // even for very slow runs.
-        long test_time_allowance = System.currentTimeMillis() +
-                                   (long)(Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) * 0.9) -
-                                   20_000;
-        long test_hard_timeout = System.currentTimeMillis() +
-                                Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT);
+        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 = test_time_allowance - System.currentTimeMillis();
-                long until_timeout = test_hard_timeout - System.currentTimeMillis();
+                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: " + until_timeout);
+                                   ", time allowance: " + allowance + ", until timeout: " + untilTimeout);
 
                 // Compute gold value, probably deopt first if constants have changed.
                 Object[] gold = test.run();
@@ -583,18 +585,18 @@ public static void main(String[] args) {
                     verify(name, gold, result);
                 }
 
-                if (System.currentTimeMillis() > test_time_allowance) {
-                    allowance = test_time_allowance - System.currentTimeMillis();
-                    until_timeout = test_hard_timeout - System.currentTimeMillis();
+                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: " + until_timeout);
+                                       ", time allowance: " + allowance + ", until timeout: " + untilTimeout);
                     return;
                 }
             }
         }
-        long allowance = test_time_allowance - System.currentTimeMillis();
-        long until_timeout = test_hard_timeout - System.currentTimeMillis();
-        System.out.println("TEST PASSED, time allowance: " + allowance + ", until timeout: " + until_timeout);
+        long allowance    = testTimeAllowance - System.currentTimeMillis();
+        long untilTimeout = testHardTimeout   - System.currentTimeMillis();
+        System.out.println("TEST PASSED, time allowance: " + allowance + ", until timeout: " + untilTimeout);
     }
 
     // Test names:

From 8c238eddce67219c3ad4b8fbe61bbcef17b939ab Mon Sep 17 00:00:00 2001
From: Kevin Walls 
Date: Mon, 15 Jan 2024 11:12:38 +0000
Subject: [PATCH 126/153] 8318707: Remove the Java Management Extension (JMX)
 Management Applet (m-let) feature

Reviewed-by: sspitsyn, dfuchs
---
 .../com/sun/jmx/defaults/JmxProperties.java   |   30 +-
 .../com/sun/jmx/defaults/ServiceName.java     |   10 +-
 .../ClassLoaderRepositorySupport.java         |   14 +-
 .../security/MBeanServerAccessController.java |   51 +-
 .../javax/management/loading/MLet.java        | 1294 -----------------
 .../javax/management/loading/MLetContent.java |  245 ----
 .../javax/management/loading/MLetMBean.java   |  190 ---
 .../loading/MLetObjectInputStream.java        |  125 --
 .../javax/management/loading/MLetParser.java  |  279 ----
 .../javax/management/loading/PrivateMLet.java |  105 --
 .../javax/management/loading/package.html     |   21 +-
 .../Introspector/ClassLeakTest.java           |   43 +-
 .../MBeanServer/PostExceptionTest.java        |   33 +-
 .../management/loading/ArrayClassTest.java    |   21 +-
 .../management/loading/DocumentRootTest.java  |   75 -
 .../loading/GetMBeansFromURLTest.java         |  105 --
 .../LibraryLoader/LibraryLoaderTest.java      |  155 --
 .../loading/LibraryLoader/UseNativeLib0.html  |   19 -
 .../loading/LibraryLoader/UseNativeLib1.html  |   19 -
 .../loading/LibraryLoader/jar_src/RandomGen.c |   15 -
 .../loading/LibraryLoader/jar_src/RandomGen.h |   15 -
 .../LibraryLoader/jar_src/UseNativeLib.java   |   36 -
 .../jar_src/UseNativeLibMBean.java            |   26 -
 .../loading/LibraryLoader/native.jar          |  Bin 4223 -> 0 bytes
 .../loading/MLetCLR/MLetCommand.java          |   65 -
 .../javax/management/loading/MLetCLR/policy   |    8 -
 .../management/loading/MLetContentTest.java   |  146 --
 .../management/loading/MLetInternalsTest.java |   93 --
 .../loading/MletParserLocaleTest.java         |  110 --
 .../loading/ParserInfiniteLoopTest.java       |  123 --
 test/jdk/javax/management/loading/mlet1.html  |    2 -
 test/jdk/javax/management/loading/mlet2.html  |    2 -
 test/jdk/javax/management/loading/mlet3.html  |    3 -
 test/jdk/javax/management/loading/mlet4.html  |    2 -
 .../management/mxbean/MXBeanLoadingTest1.java |   48 +-
 .../management/relation/NonArrayListTest.java |   21 +-
 .../mandatory/connection/IdleTimeoutTest.java |   20 +-
 .../mandatory/loading/TargetMBeanTest.java    |   37 +-
 .../notif/NotificationBufferTest.java         |    7 +-
 .../passwordAuthenticator/RMIAltAuthTest.java |    8 +-
 .../RMIPasswdAuthTest.java                    |    8 +-
 41 files changed, 139 insertions(+), 3490 deletions(-)
 delete mode 100644 src/java.management/share/classes/javax/management/loading/MLet.java
 delete mode 100644 src/java.management/share/classes/javax/management/loading/MLetContent.java
 delete mode 100644 src/java.management/share/classes/javax/management/loading/MLetMBean.java
 delete mode 100644 src/java.management/share/classes/javax/management/loading/MLetObjectInputStream.java
 delete mode 100644 src/java.management/share/classes/javax/management/loading/MLetParser.java
 delete mode 100644 src/java.management/share/classes/javax/management/loading/PrivateMLet.java
 delete mode 100644 test/jdk/javax/management/loading/DocumentRootTest.java
 delete mode 100644 test/jdk/javax/management/loading/GetMBeansFromURLTest.java
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/LibraryLoaderTest.java
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/UseNativeLib0.html
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/UseNativeLib1.html
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.c
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/jar_src/RandomGen.h
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLib.java
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/jar_src/UseNativeLibMBean.java
 delete mode 100644 test/jdk/javax/management/loading/LibraryLoader/native.jar
 delete mode 100644 test/jdk/javax/management/loading/MLetCLR/MLetCommand.java
 delete mode 100644 test/jdk/javax/management/loading/MLetCLR/policy
 delete mode 100644 test/jdk/javax/management/loading/MLetContentTest.java
 delete mode 100644 test/jdk/javax/management/loading/MLetInternalsTest.java
 delete mode 100644 test/jdk/javax/management/loading/MletParserLocaleTest.java
 delete mode 100644 test/jdk/javax/management/loading/ParserInfiniteLoopTest.java
 delete mode 100644 test/jdk/javax/management/loading/mlet1.html
 delete mode 100644 test/jdk/javax/management/loading/mlet2.html
 delete mode 100644 test/jdk/javax/management/loading/mlet3.html
 delete mode 100644 test/jdk/javax/management/loading/mlet4.html

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