1 /*
2 * Copyright (c) 2018, 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 /*
26 * @test
27 * @summary test VarHandle on value class array
28 * @enablePreview
29 * @run junit/othervm -XX:+UseArrayFlattening ArrayElementVarHandleTest
30 * @run junit/othervm -XX:-UseArrayFlattening ArrayElementVarHandleTest
31 */
32
33 import java.lang.invoke.*;
34 import java.util.stream.Stream;
35
36 import jdk.internal.vm.annotation.NullRestricted;
37 import org.junit.jupiter.params.ParameterizedTest;
38 import org.junit.jupiter.params.provider.Arguments;
39 import org.junit.jupiter.params.provider.MethodSource;
40 import static org.junit.jupiter.api.Assertions.*;
41
42 public class ArrayElementVarHandleTest {
43 static value class Point {
44 public int x;
45 public int y;
46 Point(int x, int y) {
47 this.x = x;
48 this.y = y;
49 }
50 }
51
52 static value class Line {
53 @NullRestricted
54 Point p1;
55 @NullRestricted
56 Point p2;
57
58 Line(Point p1, Point p2) {
59 this.p1 = p1;
60 this.p2 = p2;
61 }
62 Line(int x1, int y1, int x2, int y2) {
63 this(new Point(x1, y1), new Point(x2, y2));
64 }
65 }
66
67 private static final Point[] POINTS = new Point[]{
68 new Point(1, 2),
69 new Point(10, 20),
70 new Point(100, 200),
71 null
72 };
73
74 private static final Line[] LINES = new Line[]{
75 new Line(1, 2, 3, 4),
76 new Line(10, 20, 30, 40),
77 null
78 };
79
80 static Stream<Arguments> testCases() throws Throwable {
81 int plen = POINTS.length;
82 int llen = LINES.length;
83 return Stream.of(
84 Arguments.of(newArray(Object[].class, plen), POINTS),
85 Arguments.of(newArray(Object[].class, plen), new Object[] { "abc", new Point(1, 2) }),
86 Arguments.of(newArray(Point[].class, plen), POINTS),
87 Arguments.of(new Point[plen], POINTS),
88
89 Arguments.of(newArray(Object[].class, llen), LINES),
90 Arguments.of(newArray(Line[].class, llen), LINES),
91 Arguments.of(new Line[llen], LINES)
92 );
93 }
94
95 /*
96 * Constructs a new array of the specified type and size using
97 * MethodHandle.
98 */
99 private static Object[] newArray(Class<?> arrayType, int size) throws Throwable {
100 MethodHandle ctor = MethodHandles.arrayConstructor(arrayType);
101 return (Object[]) ctor.invoke(size);
102 }
103
104 /*
105 * Test VarHandle to set elements of the given array with
106 * various access mode.
107 */
108 @ParameterizedTest
109 @MethodSource("testCases")
110 public void testSetArrayElements(Object[] array, Object[] elements) {
111 Class<?> arrayType = array.getClass();
112 assertTrue(array.length >= elements.length);
113
114 VarHandle vh = MethodHandles.arrayElementVarHandle(arrayType);
115 set(vh, array.clone(), elements);
116 setVolatile(vh, array.clone(), elements);
117 setOpaque(vh, array.clone(), elements);
118 setRelease(vh, array.clone(), elements);
119 getAndSet(vh, array.clone(), elements);
120 compareAndSet(vh, array.clone(), elements);
121 compareAndExchange(vh, array.clone(), elements);
122 }
123
124 // VarHandle::set
125 void set(VarHandle vh, Object[] array, Object[] elements) {
126 for (int i = 0; i < elements.length; i++) {
127 vh.set(array, i, elements[i]);
128 }
129 for (int i = 0; i < elements.length; i++) {
130 Object v = (Object) vh.get(array, i);
131 assertEquals(elements[i], v);
132 }
133 }
134
135 // VarHandle::setVolatile
136 void setVolatile(VarHandle vh, Object[] array, Object[] elements) {
137 for (int i = 0; i < elements.length; i++) {
138 vh.setVolatile(array, i, elements[i]);
139 }
140 for (int i = 0; i < elements.length; i++) {
141 Object v = (Object) vh.getVolatile(array, i);
142 assertEquals(elements[i], v);
143 }
144 }
145
146 // VarHandle::setOpaque
147 void setOpaque(VarHandle vh, Object[] array, Object[] elements) {
148 for (int i = 0; i < elements.length; i++) {
149 vh.setOpaque(array, i, elements[i]);
150 }
151 for (int i = 0; i < elements.length; i++) {
152 Object v = (Object) vh.getOpaque(array, i);
153 assertEquals(elements[i], v);
154 }
155 }
156
157 // VarHandle::setRelease
158 void setRelease(VarHandle vh, Object[] array, Object[] elements) {
159 for (int i = 0; i < elements.length; i++) {
160 vh.setRelease(array, i, elements[i]);
161 }
162 for (int i = 0; i < elements.length; i++) {
163 Object v = (Object) vh.getAcquire(array, i);
164 assertEquals(elements[i], v);
165 }
166 }
167
168 void getAndSet(VarHandle vh, Object[] array, Object[] elements) {
169 for (int i = 0; i < elements.length; i++) {
170 Object o = vh.getAndSet(array, i, elements[i]);
171 }
172 for (int i = 0; i < elements.length; i++) {
173 Object v = (Object) vh.get(array, i);
174 assertEquals(elements[i], v);
175 }
176 }
177
178 // sanity CAS test
179 // see test/jdk/java/lang/invoke/VarHandles tests
180 void compareAndSet(VarHandle vh, Object[] array, Object[] elements) {
181 // initialize to some values
182 for (int i = 0; i < elements.length; i++) {
183 vh.set(array, i, elements[i]);
184 }
185 // shift to the right element
186 for (int i = 0; i < elements.length; i++) {
187 Object v = elements[i + 1 < elements.length ? i + 1 : 0];
188 boolean cas = vh.compareAndSet(array, i, elements[i], v);
189 if (!cas)
190 System.out.format("cas = %s array[%d] = %s vs old = %s new = %s%n", cas, i, array[i], elements[i], v);
191 assertTrue(cas);
192 }
193 }
194
195 void compareAndExchange(VarHandle vh, Object[] array, Object[] elements) {
196 // initialize to some values
197 for (int i = 0; i < elements.length; i++) {
198 vh.set(array, i, elements[i]);
199 }
200 // shift to the right element
201 for (int i = 0; i < elements.length; i++) {
202 Object v = elements[i + 1 < elements.length ? i + 1 : 0];
203 assertEquals(elements[i], vh.compareAndExchange(array, i, elements[i], v));
204 }
205 }
206 }