2727 * @summary Test that membars are eliminated when loading from a stable array.
2828 * @library /test/lib /
2929 * @modules java.base/jdk.internal.misc
30+ * @modules java.base/jdk.internal.value
3031 * @modules java.base/jdk.internal.vm.annotation
3132 * @run driver ${test.main.class}
3233 */
3334
3435package compiler .stable ;
3536
3637import java .util .Objects ;
38+ import java .util .Set ;
3739
3840import jdk .internal .misc .Unsafe ;
41+ import jdk .internal .value .ValueClass ;
3942import jdk .internal .vm .annotation .Stable ;
4043
44+ import jdk .test .lib .Asserts ;
4145import compiler .lib .ir_framework .*;
4246
4347public class TestStableArrayMembars {
4448
4549 private static final Unsafe UNSAFE = Unsafe .getUnsafe ();
4650
51+ private static final int THE_VALUE = 42 ;
52+
4753 public static void main (String [] args ) {
4854 TestFramework tf = new TestFramework ();
4955 tf .addTestClassesToBootClassPath ();
50- tf .addFlags ( "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED" );
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+ }
5164 tf .start ();
5265 }
5366
@@ -61,45 +74,70 @@ static final class LazyIntArray {
6174
6275 @ ForceInline
6376 Integer get (int idx ) {
64- Integer i = contentsAcquire (offsetFor (idx ));
77+ Integer i = contentsAcquire (offsetFor (arr , idx ));
6578 return i == null ? slowPath (arr , idx ) : i ;
6679 }
6780
6881 @ ForceInline
6982 private Integer contentsAcquire (long offset ) {
70- return (Integer ) UNSAFE .getReferenceAcquire (arr , offset );
83+ return (Integer ) (ValueClass .isFlatArray (arr ) ?
84+ UNSAFE .getFlatValueAcquire (arr , offset , UNSAFE .arrayLayout (arr ), Integer .class ) :
85+ UNSAFE .getReferenceAcquire (arr , offset ));
7186 }
7287
7388 @ ForceInline
74- private static long offsetFor (long index ) {
75- return Unsafe . ARRAY_OBJECT_BASE_OFFSET + Unsafe . ARRAY_OBJECT_INDEX_SCALE * index ;
89+ private static long offsetFor (Integer [] arr , long index ) {
90+ return UNSAFE . arrayInstanceBaseOffset ( arr ) + UNSAFE . arrayInstanceIndexScale ( arr ) * index ;
7691 }
7792
7893 static Integer slowPath (final Integer [] array , final int index ) {
79- final long offset = offsetFor (index );
94+ final long offset = offsetFor (array , index );
8095 final Integer t = array [index ];
8196 if (t == null ) {
82- final Integer newValue = Integer .valueOf (42 );
97+ final Integer newValue = Integer .valueOf (THE_VALUE );
8398 Objects .requireNonNull (newValue );
84- set (array , index , newValue );
99+ set (array , index , offset , newValue );
85100
86101 return newValue ;
87102 }
88103 return t ;
89104 }
90105
91- static void set (Integer [] array , int index , Integer newValue ) {
106+ static void set (Integer [] array , int index , long offset , Integer newValue ) {
92107 if (array [index ] == null ) {
93- UNSAFE .putReferenceRelease (array , Unsafe .ARRAY_OBJECT_BASE_OFFSET + Unsafe .ARRAY_OBJECT_INDEX_SCALE * (long ) index , newValue );
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+ }
94113 }
95114 }
96115 }
97116
98117 static final LazyIntArray la = new LazyIntArray ();
99118
100119 @ Test
101- @ IR (failOn = { IRNode .LOAD , IRNode .MEMBAR })
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 nessecary 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" })
102135 static Integer test () {
103136 return la .get (0 );
104137 }
138+
139+ @ Check (test = "test" )
140+ static void check (Integer testResult ) {
141+ Asserts .assertEQ (THE_VALUE , testResult .intValue (), "Incorrect result from LazyIntArray" );
142+ }
105143}
0 commit comments