1 /*
  2  * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @bug 8377541
 27  * @summary Test that membars are eliminated when loading from a stable array.
 28  * @library /test/lib /
 29  * @modules java.base/jdk.internal.misc
 30  * @modules java.base/jdk.internal.value
 31  * @modules java.base/jdk.internal.vm.annotation
 32  * @run driver ${test.main.class}
 33  */
 34 
 35 package compiler.stable;
 36 
 37 import java.util.Objects;
 38 import java.util.Set;
 39 
 40 import jdk.internal.misc.Unsafe;
 41 import jdk.internal.value.ValueClass;
 42 import jdk.internal.vm.annotation.Stable;
 43 
 44 import jdk.test.lib.Asserts;
 45 import compiler.lib.ir_framework.*;
 46 
 47 public class TestStableArrayMembars {
 48 
 49     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
 50 
 51     private static final int THE_VALUE = 42;
 52 
 53     public static void main(String[] args) {
 54         TestFramework tf = new TestFramework();
 55         tf.addTestClassesToBootClassPath();
 56         tf.addFlags("--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
 57                     "--add-exports=java.base/jdk.internal.value=ALL-UNNAMED");
 58         if (Integer.class.isValue()) {
 59             tf.addCrossProductScenarios(Set.of("", "-XX:-UseArrayFlattening",
 60                                                "-XX:-UseArrayFlattening -XX:-InlineTypePassFieldsAsArgs",
 61                                                "-XX:-UseArrayFlattening -XX:-InlineTypeReturnedAsFields",
 62                                                "-XX:-UseArrayFlattening -XX:-InlineTypePassFieldsAsArgs -XX:-InlineTypeReturnedAsFields"));
 63         }
 64         tf.start();
 65     }
 66 
 67     static final class LazyIntArray {
 68         @Stable
 69         private final Integer[] arr;
 70 
 71         LazyIntArray() {
 72             this.arr = new Integer[10];
 73         }
 74 
 75         @ForceInline
 76         Integer get(int idx) {
 77             Integer i = contentsAcquire(offsetFor(arr, idx));
 78             return i == null ? slowPath(arr, idx) : i;
 79         }
 80 
 81         @ForceInline
 82         private Integer contentsAcquire(long offset) {
 83             return (Integer) (ValueClass.isFlatArray(arr) ?
 84                 UNSAFE.getFlatValueAcquire(arr, offset, UNSAFE.arrayLayout(arr), Integer.class) :
 85                 UNSAFE.getReferenceAcquire(arr, offset));
 86         }
 87 
 88         @ForceInline
 89         private static long offsetFor(Integer[] arr, long index) {
 90             return UNSAFE.arrayInstanceBaseOffset(arr) + UNSAFE.arrayInstanceIndexScale(arr) * index;
 91         }
 92 
 93         static Integer slowPath(final Integer[] array, final int index) {
 94             final long offset = offsetFor(array, index);
 95             final Integer t = array[index];
 96             if (t == null) {
 97                 final Integer newValue = Integer.valueOf(THE_VALUE);
 98                 Objects.requireNonNull(newValue);
 99                 set(array, index, offset, newValue);
100 
101                 return newValue;
102             }
103             return t;
104         }
105 
106         static void set(Integer[] array, int index, long offset, Integer newValue) {
107             if (array[index] == null) {
108                 if (!ValueClass.isFlatArray(array)) {
109                     UNSAFE.putReferenceRelease(array, offset, newValue);
110                 } else {
111                     UNSAFE.putFlatValueRelease(array, offset, UNSAFE.arrayLayout(array), Integer.class, newValue);
112                 }
113             }
114         }
115     }
116 
117     static final LazyIntArray la = new LazyIntArray();
118 
119     @Test
120     // We cannot eliminate all barriers with flat arrays, because Unsafe.getFlatValueAcquire()
121     // explicitly adds a loadFence() in Java. Hence, there is no way for C2 to correlate those
122     // barriers to an eliminated memory access and thus no way to remove them.
123     // The barrier elimination only works with tiered compilation as the profiling information
124     // is necessary to inline the low-frequency Unsafe.put* methods.
125     @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR },
126         applyIfAnd = {"enable-valhalla", "false",
127                       "TieredCompilation", "true"})
128     @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR },
129         applyIfAnd = {"UseArrayFlattening", "false",
130                       "TieredCompilation", "true"})
131     @IR(counts = { IRNode.MEMBAR, ">0",
132                    IRNode.LOAD, "=1"}, // There is exactly one load fence, but no load
133         applyIfAnd = {"enable-valhalla", "true",
134                       "UseArrayFlattening", "true",
135                       "TieredCompilation", "true"})
136     static Integer test() {
137         return la.get(0);
138     }
139 
140     @Check(test = "test")
141     static void check(Integer testResult) {
142         Asserts.assertEQ(THE_VALUE, testResult.intValue(), "Incorrect result from LazyIntArray");
143     }
144 }
--- EOF ---