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