1 /*
  2  * Copyright (c) 2015, 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 import java.lang.invoke.VarHandle;
 25 import java.nio.ByteBuffer;
 26 import java.nio.ByteOrder;
 27 import java.util.ArrayList;
 28 import java.util.Arrays;
 29 import java.util.EnumSet;
 30 import java.util.List;
 31 import java.util.function.Function;
 32 import org.junit.jupiter.api.BeforeAll;
 33 
 34 public abstract class VarHandleBaseByteArrayTest extends VarHandleBaseTest {
 35 
 36     enum MemoryMode {
 37         ALIGNED(0, false), UNALIGNED(0, true),
 38         BIG_ENDIAN(1, false), LITTLE_ENDIAN(1, true),
 39         READ_WRITE(2, false), READ_ONLY(2, true),;
 40 
 41         final int bit;
 42         final int value;
 43 
 44         MemoryMode(int bit, boolean value) {
 45             this.bit = bit;
 46             this.value = value ? 1 << bit : 0;
 47         }
 48 
 49         boolean isSet(int bitSet) {
 50             return (bitSet & (1 << bit)) == value;
 51         }
 52 
 53         static int bitSet(MemoryMode... modes) {
 54             if (modes == null) return 0;
 55 
 56             int set = 0;
 57             for (MemoryMode m : modes) {
 58                 set = (set & ~(1 << m.bit)) | m.value;
 59             }
 60             return set;
 61         }
 62 
 63         static EnumSet<MemoryMode> enumSet(int bitSet) {
 64             EnumSet<MemoryMode> es = EnumSet.noneOf(MemoryMode.class);
 65             for (MemoryMode m : values()) {
 66                 if (m.isSet(bitSet)) {
 67                     es.add(m);
 68                 }
 69             }
 70             return es;
 71         }
 72     }
 73 
 74     static class Source<T> {
 75         final T s;
 76         final int memoryModes;
 77 
 78         public Source(T s, MemoryMode... modes) {
 79             this.s = s;
 80             memoryModes = MemoryMode.bitSet(modes);
 81         }
 82 
 83         @Override
 84         public String toString() {
 85             return s.getClass().getCanonicalName() + " " + MemoryMode.enumSet(memoryModes);
 86         }
 87     }
 88 
 89     static abstract class ByteArrayViewSource<T> extends Source<T> {
 90         public ByteArrayViewSource(T t, MemoryMode... modes) {
 91             super(t, modes);
 92         }
 93 
 94         abstract void fill(byte value);
 95 
 96         abstract void fill(byte[] values);
 97     }
 98 
 99     static class ByteArraySource extends ByteArrayViewSource<byte[]> {
100         public ByteArraySource(byte[] bytes, MemoryMode... modes) {
101             super(bytes, modes);
102         }
103 
104         void fill(byte value) {
105             Arrays.fill(s, value);
106         }
107 
108         void fill(byte[] values) {
109             for (int i = 0; i < s.length; i++) {
110                 s[i] = values[i % values.length];
111             }
112         }
113     }
114 
115     static class ByteBufferSource extends ByteArrayViewSource<ByteBuffer> {
116         public ByteBufferSource(ByteBuffer buffer, MemoryMode... modes) {
117             super(buffer, modes);
118         }
119 
120         void fill(byte value) {
121             for (int i = 0; i < s.limit(); i++) {
122                 s.put(i, value);
123             }
124         }
125 
126         void fill(byte[] values) {
127             for (int i = 0; i < s.limit(); i++) {
128                 s.put(i, values[i % values.length]);
129             }
130         }
131 
132         @Override
133         public String toString() {
134             return s + " " + MemoryMode.enumSet(memoryModes);
135         }
136     }
137 
138     static class ByteBufferReadOnlySource extends ByteBufferSource {
139         final ByteBuffer rwSource;
140 
141         public ByteBufferReadOnlySource(ByteBuffer roBuffer, ByteBuffer rwSource, MemoryMode... modes) {
142             super(roBuffer, modes);
143             this.rwSource = rwSource;
144         }
145 
146         void fill(byte value) {
147             for (int i = 0; i < rwSource.limit(); i++) {
148                 rwSource.put(i, value);
149             }
150         }
151 
152         void fill(byte[] values) {
153             for (int i = 0; i < rwSource.limit(); i++) {
154                 rwSource.put(i, values[i % values.length]);
155             }
156         }
157     }
158 
159     static class VarHandleSource extends Source<VarHandle> {
160         final boolean supportsAtomicAccess;
161 
162         VarHandleSource(VarHandle vh, boolean supportsAtomicAccess, MemoryMode... modes) {
163             super(vh, modes);
164             this.supportsAtomicAccess = supportsAtomicAccess;
165         }
166 
167         boolean matches(ByteArrayViewSource<?> bav) {
168             return s.coordinateTypes().get(0).isAssignableFrom(bav.s.getClass());
169         }
170 
171         @Override
172         public String toString() {
173             return " VarHandle " + MemoryMode.enumSet(memoryModes);
174         }
175     }
176 
177     static class VarHandleSourceAccessTestCase extends AccessTestCase<VarHandleSource> {
178         final ByteArrayViewSource<?> bs;
179         final VarHandleSource vhs;
180 
181         VarHandleSourceAccessTestCase(String desc, ByteArrayViewSource<?> bs, VarHandleSource vhs, AccessTestAction<VarHandleSource> ata) {
182             this(desc, bs, vhs, ata, true);
183         }
184 
185         VarHandleSourceAccessTestCase(String desc, ByteArrayViewSource<?> bs, VarHandleSource vhs, AccessTestAction<VarHandleSource> ata, boolean loop) {
186             super(vhs + " -> " + bs + " " + desc, ata, loop);
187             this.bs = bs;
188             this.vhs = vhs;
189         }
190 
191         @Override
192         VarHandleSource get() {
193             return vhs;
194         }
195     }
196 
197 
198     static double rotateLeft(double i, int distance) {
199         return Double.longBitsToDouble(
200                 Long.rotateLeft(Double.doubleToRawLongBits(i), distance));
201     }
202 
203     static double rotateRight(double i, int distance) {
204         return Double.longBitsToDouble(
205                 Long.rotateRight(Double.doubleToRawLongBits(i), distance));
206     }
207 
208     static float rotateLeft(float i, int distance) {
209         return Float.intBitsToFloat(
210                 Integer.rotateLeft(Float.floatToRawIntBits(i), distance));
211     }
212 
213     static float rotateRight(float i, int distance) {
214         return Float.intBitsToFloat(
215                 Integer.rotateRight(Float.floatToRawIntBits(i), distance));
216     }
217 
218     static long rotateLeft(long i, int distance) {
219         return Long.rotateLeft(i, distance);
220     }
221 
222     static long rotateRight(long i, int distance) {
223         return Long.rotateRight(i, distance);
224     }
225 
226     static int rotateLeft(int i, int distance) {
227         return Integer.rotateLeft(i, distance);
228     }
229 
230     static int rotateRight(int i, int distance) {
231         return Integer.rotateRight(i, distance);
232     }
233 
234     static short rotateLeft(short i, int distance) {
235         int v = (i << 16) | i;
236         v = Integer.rotateLeft(v, distance);
237         return (short) v;
238     }
239 
240     static short rotateRight(short i, int distance) {
241         int v = (i << 16) | i;
242         v = Integer.rotateRight(v, distance);
243         return (short) v;
244     }
245 
246     static char rotateLeft(char i, int distance) {
247         int v = (i << 16) | i;
248         v = Integer.rotateLeft(v, distance);
249         return (char) v;
250     }
251 
252     static char rotateRight(char i, int distance) {
253         int v = (i << 16) | i;
254         v = Integer.rotateRight(v, distance);
255         return (char) v;
256     }
257 
258     static final int LENGTH_BYTES = 32;
259 
260     byte[] array;
261 
262     List<ByteArrayViewSource<?>> bavss;
263 
264     List<VarHandleSource> vhss;
265 
266     public void setupByteSources() {
267         array = new byte[LENGTH_BYTES];
268 
269         // Native endianess
270         MemoryMode ne = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN
271                         ? MemoryMode.BIG_ENDIAN : MemoryMode.LITTLE_ENDIAN;
272 
273         bavss = new ArrayList<>();
274 
275         // byte[] source
276         ByteArraySource a =
277                 new ByteArraySource(array,
278                                     ne, MemoryMode.READ_WRITE);
279         bavss.add(a);
280 
281 
282         // Combinations of ByteBuffer sources
283         ByteBufferSource hbb =
284                 new ByteBufferSource(ByteBuffer.wrap(array),
285                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
286         bavss.add(hbb);
287         ByteBufferReadOnlySource hbb_ro =
288                 new ByteBufferReadOnlySource(hbb.s.asReadOnlyBuffer(), hbb.s,
289                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
290         bavss.add(hbb_ro);
291 
292         ByteBufferSource hbb_offset_aligned =
293                 new ByteBufferSource(ByteBuffer.wrap(array, array.length / 4, array.length / 2).slice(),
294                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
295         bavss.add(hbb_offset_aligned);
296         ByteBufferReadOnlySource hbb_offset_aligned_ro =
297                 new ByteBufferReadOnlySource(hbb_offset_aligned.s.asReadOnlyBuffer(), hbb_offset_aligned.s,
298                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
299         bavss.add(hbb_offset_aligned_ro);
300 
301         ByteBufferSource hbb_offset_unaligned =
302                 new ByteBufferSource(ByteBuffer.wrap(array, array.length / 4 - 1, array.length / 2).slice(),
303                                      MemoryMode.UNALIGNED, ne, MemoryMode.READ_WRITE);
304         bavss.add(hbb_offset_unaligned);
305         ByteBufferReadOnlySource hbb_offset_unaligned_ro =
306                 new ByteBufferReadOnlySource(hbb_offset_unaligned.s.asReadOnlyBuffer(), hbb_offset_unaligned.s,
307                                              MemoryMode.UNALIGNED, ne, MemoryMode.READ_ONLY);
308         bavss.add(hbb_offset_unaligned_ro);
309 
310 
311         ByteBufferSource dbb =
312                 new ByteBufferSource(ByteBuffer.allocateDirect(array.length),
313                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
314         bavss.add(dbb);
315         ByteBufferReadOnlySource dbb_ro =
316                 new ByteBufferReadOnlySource(dbb.s.asReadOnlyBuffer(), dbb.s,
317                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
318         bavss.add(dbb_ro);
319 
320         ByteBufferSource dbb_offset_aligned =
321                 new ByteBufferSource(dbb.s.slice().position(array.length / 4).limit(array.length / 4 + array.length / 2).slice(),
322                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
323         bavss.add(dbb_offset_aligned);
324         ByteBufferReadOnlySource dbb_offset_aligned_ro =
325                 new ByteBufferReadOnlySource(dbb_offset_aligned.s.asReadOnlyBuffer(), dbb_offset_aligned.s,
326                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
327         bavss.add(dbb_offset_aligned_ro);
328 
329         ByteBufferSource dbb_offset_unaligned =
330                 new ByteBufferSource(dbb.s.slice().position(array.length / 4 - 1).limit(array.length / 4 - 1 + array.length / 2).slice(),
331                                      MemoryMode.UNALIGNED, ne, MemoryMode.READ_WRITE);
332         bavss.add(dbb_offset_unaligned);
333         ByteBufferReadOnlySource dbb_offset_unaligned_ro =
334                 new ByteBufferReadOnlySource(dbb_offset_unaligned.s.asReadOnlyBuffer(), dbb_offset_unaligned.s,
335                                              MemoryMode.UNALIGNED, ne, MemoryMode.READ_ONLY);
336         bavss.add(dbb_offset_unaligned_ro);
337     }
338 
339     @BeforeAll
340     public void setup() {
341         setupByteSources();
342         vhss = setupVarHandleSources(true);
343     }
344 
345     abstract List<VarHandleSource> setupVarHandleSources(boolean same);
346 
347     public Object[][] varHandlesProvider() throws Exception {
348         return vhss.stream().map(cvh -> new Object[]{cvh}).toArray(Object[][]::new);
349     }
350 
351     public Object[][] typesProvider() throws Exception {
352         List<java.lang.Class<?>> aepts = Arrays.asList(byte[].class, int.class);
353         List<java.lang.Class<?>> bbpts = Arrays.asList(ByteBuffer.class, int.class);
354 
355         Function<VarHandle, List<Class<?>>> vhToPts = vh ->
356                 vh.coordinateTypes().get(0) == byte[].class ? aepts : bbpts;
357 
358         return vhss.stream().map(vh -> new Object[]{vh.s, vhToPts.apply(vh.s)}).toArray(Object[][]::new);
359     }
360 }