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         public String toString() {
197             return super.toString() + ", bs: " + bs + ", vhs: " + vhs;
198         }
199     }
200 
201 
202     static double rotateLeft(double i, int distance) {
203         return Double.longBitsToDouble(
204                 Long.rotateLeft(Double.doubleToRawLongBits(i), distance));
205     }
206 
207     static double rotateRight(double i, int distance) {
208         return Double.longBitsToDouble(
209                 Long.rotateRight(Double.doubleToRawLongBits(i), distance));
210     }
211 
212     static float rotateLeft(float i, int distance) {
213         return Float.intBitsToFloat(
214                 Integer.rotateLeft(Float.floatToRawIntBits(i), distance));
215     }
216 
217     static float rotateRight(float i, int distance) {
218         return Float.intBitsToFloat(
219                 Integer.rotateRight(Float.floatToRawIntBits(i), distance));
220     }
221 
222     static long rotateLeft(long i, int distance) {
223         return Long.rotateLeft(i, distance);
224     }
225 
226     static long rotateRight(long i, int distance) {
227         return Long.rotateRight(i, distance);
228     }
229 
230     static int rotateLeft(int i, int distance) {
231         return Integer.rotateLeft(i, distance);
232     }
233 
234     static int rotateRight(int i, int distance) {
235         return Integer.rotateRight(i, distance);
236     }
237 
238     static short rotateLeft(short i, int distance) {
239         int v = (i << 16) | i;
240         v = Integer.rotateLeft(v, distance);
241         return (short) v;
242     }
243 
244     static short rotateRight(short i, int distance) {
245         int v = (i << 16) | i;
246         v = Integer.rotateRight(v, distance);
247         return (short) v;
248     }
249 
250     static char rotateLeft(char i, int distance) {
251         int v = (i << 16) | i;
252         v = Integer.rotateLeft(v, distance);
253         return (char) v;
254     }
255 
256     static char rotateRight(char i, int distance) {
257         int v = (i << 16) | i;
258         v = Integer.rotateRight(v, distance);
259         return (char) v;
260     }
261 
262     static final int LENGTH_BYTES = 32;
263 
264     byte[] array;
265 
266     List<ByteArrayViewSource<?>> bavss;
267 
268     List<VarHandleSource> vhss;
269 
270     public void setupByteSources() {
271         array = new byte[LENGTH_BYTES];
272 
273         // Native endianess
274         MemoryMode ne = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN
275                         ? MemoryMode.BIG_ENDIAN : MemoryMode.LITTLE_ENDIAN;
276 
277         bavss = new ArrayList<>();
278 
279         // byte[] source
280         ByteArraySource a =
281                 new ByteArraySource(array,
282                                     ne, MemoryMode.READ_WRITE);
283         bavss.add(a);
284 
285 
286         // Combinations of ByteBuffer sources
287         ByteBufferSource hbb =
288                 new ByteBufferSource(ByteBuffer.wrap(array),
289                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
290         bavss.add(hbb);
291         ByteBufferReadOnlySource hbb_ro =
292                 new ByteBufferReadOnlySource(hbb.s.asReadOnlyBuffer(), hbb.s,
293                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
294         bavss.add(hbb_ro);
295 
296         ByteBufferSource hbb_offset_aligned =
297                 new ByteBufferSource(ByteBuffer.wrap(array, array.length / 4, array.length / 2).slice(),
298                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
299         bavss.add(hbb_offset_aligned);
300         ByteBufferReadOnlySource hbb_offset_aligned_ro =
301                 new ByteBufferReadOnlySource(hbb_offset_aligned.s.asReadOnlyBuffer(), hbb_offset_aligned.s,
302                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
303         bavss.add(hbb_offset_aligned_ro);
304 
305         ByteBufferSource hbb_offset_unaligned =
306                 new ByteBufferSource(ByteBuffer.wrap(array, array.length / 4 - 1, array.length / 2).slice(),
307                                      MemoryMode.UNALIGNED, ne, MemoryMode.READ_WRITE);
308         bavss.add(hbb_offset_unaligned);
309         ByteBufferReadOnlySource hbb_offset_unaligned_ro =
310                 new ByteBufferReadOnlySource(hbb_offset_unaligned.s.asReadOnlyBuffer(), hbb_offset_unaligned.s,
311                                              MemoryMode.UNALIGNED, ne, MemoryMode.READ_ONLY);
312         bavss.add(hbb_offset_unaligned_ro);
313 
314 
315         ByteBufferSource dbb =
316                 new ByteBufferSource(ByteBuffer.allocateDirect(array.length),
317                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
318         bavss.add(dbb);
319         ByteBufferReadOnlySource dbb_ro =
320                 new ByteBufferReadOnlySource(dbb.s.asReadOnlyBuffer(), dbb.s,
321                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
322         bavss.add(dbb_ro);
323 
324         ByteBufferSource dbb_offset_aligned =
325                 new ByteBufferSource(dbb.s.slice().position(array.length / 4).limit(array.length / 4 + array.length / 2).slice(),
326                                      MemoryMode.ALIGNED, ne, MemoryMode.READ_WRITE);
327         bavss.add(dbb_offset_aligned);
328         ByteBufferReadOnlySource dbb_offset_aligned_ro =
329                 new ByteBufferReadOnlySource(dbb_offset_aligned.s.asReadOnlyBuffer(), dbb_offset_aligned.s,
330                                              MemoryMode.ALIGNED, ne, MemoryMode.READ_ONLY);
331         bavss.add(dbb_offset_aligned_ro);
332 
333         ByteBufferSource dbb_offset_unaligned =
334                 new ByteBufferSource(dbb.s.slice().position(array.length / 4 - 1).limit(array.length / 4 - 1 + array.length / 2).slice(),
335                                      MemoryMode.UNALIGNED, ne, MemoryMode.READ_WRITE);
336         bavss.add(dbb_offset_unaligned);
337         ByteBufferReadOnlySource dbb_offset_unaligned_ro =
338                 new ByteBufferReadOnlySource(dbb_offset_unaligned.s.asReadOnlyBuffer(), dbb_offset_unaligned.s,
339                                              MemoryMode.UNALIGNED, ne, MemoryMode.READ_ONLY);
340         bavss.add(dbb_offset_unaligned_ro);
341     }
342 
343     @BeforeAll
344     public void setup() {
345         setupByteSources();
346         vhss = setupVarHandleSources(true);
347     }
348 
349     abstract List<VarHandleSource> setupVarHandleSources(boolean same);
350 
351     public Object[][] varHandlesProvider() throws Exception {
352         return vhss.stream().map(cvh -> new Object[]{cvh}).toArray(Object[][]::new);
353     }
354 
355     public Object[][] typesProvider() throws Exception {
356         List<java.lang.Class<?>> aepts = Arrays.asList(byte[].class, int.class);
357         List<java.lang.Class<?>> bbpts = Arrays.asList(ByteBuffer.class, int.class);
358 
359         Function<VarHandle, List<Class<?>>> vhToPts = vh ->
360                 vh.coordinateTypes().get(0) == byte[].class ? aepts : bbpts;
361 
362         return vhss.stream().map(vh -> new Object[]{vh.s, vhToPts.apply(vh.s)}).toArray(Object[][]::new);
363     }
364 }