1 /*
  2  * Copyright (c) 2019, 2020, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 /*
 27  * @test
 28  * @modules java.base/sun.nio.ch
 29  *          jdk.incubator.foreign/jdk.internal.foreign
 30  * @run testng TestByteBuffer
 31  */
 32 
 33 
 34 import jdk.incubator.foreign.MappedMemorySegment;
 35 import jdk.incubator.foreign.MemoryLayouts;
 36 import jdk.incubator.foreign.MemoryLayout;
 37 import jdk.incubator.foreign.MemoryAddress;
 38 import jdk.incubator.foreign.MemorySegment;
 39 import jdk.incubator.foreign.MemoryLayout.PathElement;
 40 import jdk.incubator.foreign.SequenceLayout;
 41 
 42 import java.io.File;
 43 import java.io.IOException;
 44 import java.lang.invoke.MethodHandle;
 45 import java.lang.invoke.MethodHandles;
 46 import java.lang.invoke.VarHandle;
 47 import java.lang.ref.WeakReference;
 48 import java.lang.reflect.InvocationTargetException;
 49 import java.lang.reflect.Method;
 50 import java.lang.reflect.Modifier;
 51 import java.nio.Buffer;
 52 import java.nio.ByteBuffer;
 53 import java.nio.ByteOrder;
 54 import java.nio.CharBuffer;
 55 import java.nio.DoubleBuffer;
 56 import java.nio.FloatBuffer;
 57 import java.nio.IntBuffer;
 58 import java.nio.LongBuffer;
 59 import java.nio.MappedByteBuffer;
 60 import java.nio.ShortBuffer;
 61 import java.nio.channels.FileChannel;
 62 import java.nio.file.Files;
 63 import java.nio.file.Path;
 64 import java.nio.file.StandardOpenOption;
 65 import java.util.HashMap;
 66 import java.util.Map;
 67 import java.util.function.BiConsumer;
 68 import java.util.function.BiFunction;
 69 import java.util.function.Consumer;
 70 import java.util.function.Function;
 71 import java.util.function.Predicate;
 72 import java.util.stream.Stream;
 73 
 74 import jdk.internal.foreign.HeapMemorySegmentImpl;
 75 import jdk.internal.foreign.MappedMemorySegmentImpl;
 76 import jdk.internal.foreign.MemoryAddressImpl;
 77 import jdk.internal.foreign.NativeMemorySegmentImpl;
 78 import org.testng.SkipException;
 79 import org.testng.annotations.*;
 80 import sun.nio.ch.DirectBuffer;
 81 
 82 import static org.testng.Assert.*;
 83 
 84 public class TestByteBuffer {
 85 
 86     static Path tempPath;
 87 
 88     static {
 89         try {
 90             File file = File.createTempFile("buffer", "txt");
 91             file.deleteOnExit();
 92             tempPath = file.toPath();
 93             Files.write(file.toPath(), new byte[256], StandardOpenOption.WRITE);
 94 
 95         } catch (IOException ex) {
 96             throw new ExceptionInInitializerError(ex);
 97         }
 98     }
 99 
100     static SequenceLayout tuples = MemoryLayout.ofSequence(500,
101             MemoryLayout.ofStruct(
102                     MemoryLayouts.BITS_32_BE.withName("index"),
103                     MemoryLayouts.BITS_32_BE.withName("value")
104             ));
105 
106     static SequenceLayout bytes = MemoryLayout.ofSequence(100,
107             MemoryLayouts.BITS_8_BE
108     );
109 
110     static SequenceLayout chars = MemoryLayout.ofSequence(100,
111             MemoryLayouts.BITS_16_BE
112     );
113 
114     static SequenceLayout shorts = MemoryLayout.ofSequence(100,
115             MemoryLayouts.BITS_16_BE
116     );
117 
118     static SequenceLayout ints = MemoryLayout.ofSequence(100,
119             MemoryLayouts.BITS_32_BE
120     );
121 
122     static SequenceLayout floats = MemoryLayout.ofSequence(100,
123             MemoryLayouts.BITS_32_BE
124     );
125 
126     static SequenceLayout longs = MemoryLayout.ofSequence(100,
127             MemoryLayouts.BITS_64_BE
128     );
129 
130     static SequenceLayout doubles = MemoryLayout.ofSequence(100,
131             MemoryLayouts.BITS_64_BE
132     );
133 
134     static VarHandle indexHandle = tuples.varHandle(int.class, PathElement.sequenceElement(), PathElement.groupElement("index"));
135     static VarHandle valueHandle = tuples.varHandle(float.class, PathElement.sequenceElement(), PathElement.groupElement("value"));
136 
137     static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement());
138     static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement());
139     static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement());
140     static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement());
141     static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement());
142     static VarHandle longHandle = longs.varHandle(long.class, PathElement.sequenceElement());
143     static VarHandle doubleHandle = doubles.varHandle(double.class, PathElement.sequenceElement());
144 
145 
146     static void initTuples(MemoryAddress base) {
147         for (long i = 0; i < tuples.elementCount().getAsLong() ; i++) {
148             indexHandle.set(base, i, (int)i);
149             valueHandle.set(base, i, (float)(i / 500f));
150         }
151     }
152 
153     static void checkTuples(MemoryAddress base, ByteBuffer bb) {
154         for (long i = 0; i < tuples.elementCount().getAsLong() ; i++) {
155             assertEquals(bb.getInt(), (int)indexHandle.get(base, i));
156             assertEquals(bb.getFloat(), (float)valueHandle.get(base, i));
157         }
158     }
159 
160     static void initBytes(MemoryAddress base, SequenceLayout seq, BiConsumer<MemoryAddress, Long> handleSetter) {
161         for (long i = 0; i < seq.elementCount().getAsLong() ; i++) {
162             handleSetter.accept(base, i);
163         }
164     }
165 
166     static <Z extends Buffer> void checkBytes(MemoryAddress base, SequenceLayout layout,
167                                               Function<ByteBuffer, Z> bufFactory,
168                                               BiFunction<MemoryAddress, Long, Object> handleExtractor,
169                                               Function<Z, Object> bufferExtractor) {
170         long nelems = layout.elementCount().getAsLong();
171         long elemSize = layout.elementLayout().byteSize();
172         for (long i = 0 ; i < nelems ; i++) {
173             long limit = nelems - i;
174             MemorySegment resizedSegment = base.segment().asSlice(i * elemSize, limit * elemSize);
175             ByteBuffer bb = resizedSegment.asByteBuffer();
176             Z z = bufFactory.apply(bb);
177             for (long j = i ; j < limit ; j++) {
178                 Object handleValue = handleExtractor.apply(resizedSegment.baseAddress(), j - i);
179                 Object bufferValue = bufferExtractor.apply(z);
180                 if (handleValue instanceof Number) {
181                     assertEquals(((Number)handleValue).longValue(), j);
182                     assertEquals(((Number)bufferValue).longValue(), j);
183                 } else {
184                     assertEquals((long)(char)handleValue, j);
185                     assertEquals((long)(char)bufferValue, j);
186                 }
187             }
188         }
189     }
190 
191     @Test
192     public void testOffheap() {
193         try (MemorySegment segment = MemorySegment.allocateNative(tuples)) {
194             MemoryAddress base = segment.baseAddress();
195             initTuples(base);
196 
197             ByteBuffer bb = segment.asByteBuffer();
198             checkTuples(base, bb);
199         }
200     }
201 
202     @Test
203     public void testHeap() {
204         byte[] arr = new byte[(int) tuples.byteSize()];
205         MemorySegment region = MemorySegment.ofArray(arr);
206         MemoryAddress base = region.baseAddress();
207         initTuples(base);
208 
209         ByteBuffer bb = region.asByteBuffer();
210         checkTuples(base, bb);
211     }
212 
213     @Test
214     public void testChannel() throws Throwable {
215         File f = new File("test.out");
216         assertTrue(f.createNewFile());
217         f.deleteOnExit();
218 
219         //write to channel
220         try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
221             withMappedBuffer(channel, FileChannel.MapMode.READ_WRITE, 0, tuples.byteSize(), mbb -> {
222                 MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
223                 MemoryAddress base = segment.baseAddress();
224                 initTuples(base);
225                 mbb.force();
226             });
227         }
228 
229         //read from channel
230         try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
231             withMappedBuffer(channel, FileChannel.MapMode.READ_ONLY, 0, tuples.byteSize(), mbb -> {
232                 MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
233                 MemoryAddress base = segment.baseAddress();
234                 checkTuples(base, mbb);
235             });
236         }
237     }
238 
239     @Test
240     public void testMappedSegment() throws Throwable {
241         File f = new File("test2.out");
242         f.createNewFile();
243         f.deleteOnExit();
244 
245         //write to channel
246         try (MappedMemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_WRITE)) {
247             MemoryAddress base = segment.baseAddress();
248             initTuples(base);
249             segment.force();
250         }
251 
252         //read from channel
253         try (MemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_ONLY)) {
254             MemoryAddress base = segment.baseAddress();
255             checkTuples(base, segment.asByteBuffer());
256         }
257     }
258 
259     static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action) throws Throwable {
260         MappedByteBuffer mbb = channel.map(mode, pos, size);
261         var ref = new WeakReference<>(mbb);
262         action.accept(mbb);
263         mbb = null;
264         //wait for it to be GCed
265         System.gc();
266         while (ref.get() != null) {
267             Thread.sleep(20);
268         }
269     }
270 
271     static void checkByteArrayAlignment(MemoryLayout layout) {
272         if (layout.bitSize() > 32
273                 && System.getProperty("sun.arch.data.model").equals("32")) {
274             throw new SkipException("avoid unaligned access on 32-bit system");
275         }
276     }
277 
278     @Test(dataProvider = "bufferOps")
279     public void testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
280         Buffer bb;
281         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
282             MemoryAddress base = segment.baseAddress();
283             bb = bufferFactory.apply(segment.asByteBuffer());
284         }
285         //outside of scope!!
286         for (Map.Entry<Method, Object[]> e : members.entrySet()) {
287             if (!e.getKey().getName().contains("get") &&
288                             !e.getKey().getName().contains("put")) {
289                 //skip
290                 return;
291             }
292             try {
293                 e.getKey().invoke(bb, e.getValue());
294                 assertTrue(false);
295             } catch (InvocationTargetException ex) {
296                 Throwable cause = ex.getCause();
297                 if (cause instanceof IllegalStateException) {
298                     //all get/set buffer operation should fail because of the scope check
299                     assertTrue(ex.getCause().getMessage().contains("already closed"));
300                 } else {
301                     //all other exceptions were unexpected - fail
302                     assertTrue(false);
303                 }
304             } catch (Throwable ex) {
305                 //unexpected exception - fail
306                 assertTrue(false);
307             }
308         }
309     }
310 
311     @Test(dataProvider = "bufferHandleOps")
312     public void testScopedBufferAndVarHandle(VarHandle bufferHandle) {
313         ByteBuffer bb;
314         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
315             bb = segment.asByteBuffer();
316             for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
317                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
318                         .asSpreader(Object[].class, e.getValue().length);
319                 try {
320                     handle.invoke(e.getValue());
321                 } catch (UnsupportedOperationException ex) {
322                     //skip
323                 } catch (Throwable ex) {
324                     //should not fail - segment is alive!
325                     fail();
326                 }
327             }
328         }
329         for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
330             try {
331                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
332                         .asSpreader(Object[].class, e.getValue().length);
333                 handle.invoke(e.getValue());
334                 fail();
335             } catch (IllegalStateException ex) {
336                 assertTrue(ex.getMessage().contains("already closed"));
337             } catch (UnsupportedOperationException ex) {
338                 //skip
339             } catch (Throwable ex) {
340                 fail();
341             }
342         }
343     }
344 
345     @Test(dataProvider = "bufferOps")
346     public void testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
347         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
348             MemoryAddress base = segment.baseAddress();
349             Buffer bb = bufferFactory.apply(segment.asByteBuffer());
350             assertTrue(bb.isDirect());
351             DirectBuffer directBuffer = ((DirectBuffer)bb);
352             assertEquals(directBuffer.address(), ((MemoryAddressImpl)base).unsafeGetOffset());
353             assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer));
354             assertTrue(directBuffer.cleaner() == null);
355         }
356     }
357 
358     @Test(dataProvider="resizeOps")
359     public void testResizeOffheap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
360         try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
361             MemoryAddress base = segment.baseAddress();
362             initializer.accept(base);
363             checker.accept(base);
364         }
365     }
366 
367     @Test(dataProvider="resizeOps")
368     public void testResizeHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
369         checkByteArrayAlignment(seq.elementLayout());
370         int capacity = (int)seq.byteSize();
371         MemoryAddress base = MemorySegment.ofArray(new byte[capacity]).baseAddress();
372         initializer.accept(base);
373         checker.accept(base);
374     }
375 
376     @Test(dataProvider="resizeOps")
377     public void testResizeBuffer(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
378         checkByteArrayAlignment(seq.elementLayout());
379         int capacity = (int)seq.byteSize();
380         MemoryAddress base = MemorySegment.ofByteBuffer(ByteBuffer.wrap(new byte[capacity])).baseAddress();
381         initializer.accept(base);
382         checker.accept(base);
383     }
384 
385     @Test(dataProvider="resizeOps")
386     public void testResizeRoundtripHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
387         checkByteArrayAlignment(seq.elementLayout());
388         int capacity = (int)seq.byteSize();
389         byte[] arr = new byte[capacity];
390         MemorySegment segment = MemorySegment.ofArray(arr);
391         MemoryAddress first = segment.baseAddress();
392         initializer.accept(first);
393         MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
394         checker.accept(second);
395     }
396 
397     @Test(dataProvider="resizeOps")
398     public void testResizeRoundtripNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
399         try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
400             MemoryAddress first = segment.baseAddress();
401             initializer.accept(first);
402             MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
403             checker.accept(second);
404         }
405     }
406 
407     @Test(expectedExceptions = IllegalStateException.class)
408     public void testBufferOnClosedScope() {
409         MemorySegment leaked;
410         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
411             leaked = segment;
412         }
413         ByteBuffer byteBuffer = leaked.asByteBuffer(); // ok
414         byteBuffer.get(); // should throw
415     }
416 
417     @Test(expectedExceptions = { UnsupportedOperationException.class,
418                                  IllegalArgumentException.class })
419     public void testTooBigForByteBuffer() {
420         try (MemorySegment segment = MemorySegment.allocateNative((long)Integer.MAX_VALUE + 10L)) {
421             segment.asByteBuffer();
422         }
423     }
424 
425     @Test(dataProvider="resizeOps")
426     public void testCopyHeapToNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
427         checkByteArrayAlignment(seq.elementLayout());
428         int bytes = (int)seq.byteSize();
429         try (MemorySegment nativeArray = MemorySegment.allocateNative(bytes);
430              MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
431             initializer.accept(heapArray.baseAddress());
432             nativeArray.copyFrom(heapArray);
433             checker.accept(nativeArray.baseAddress());
434         }
435     }
436 
437     @Test(dataProvider="resizeOps")
438     public void testCopyNativeToHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
439         checkByteArrayAlignment(seq.elementLayout());
440         int bytes = (int)seq.byteSize();
441         try (MemorySegment nativeArray = MemorySegment.allocateNative(seq);
442              MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
443             initializer.accept(nativeArray.baseAddress());
444             heapArray.copyFrom(nativeArray);
445             checker.accept(heapArray.baseAddress());
446         }
447     }
448 
449     @Test(dataProvider="bufferSources")
450     public void testBufferToSegment(ByteBuffer bb, Predicate<MemorySegment> segmentChecker) {
451         MemorySegment segment = MemorySegment.ofByteBuffer(bb);
452         assertEquals(segment.hasAccessModes(MemorySegment.WRITE), !bb.isReadOnly());
453         assertTrue(segmentChecker.test(segment));
454         assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
455         assertTrue(segmentChecker.test(segment.withAccessModes(MemorySegment.READ)));
456         assertEquals(bb.capacity(), segment.byteSize());
457         //another round trip
458         segment = MemorySegment.ofByteBuffer(segment.asByteBuffer());
459         assertEquals(segment.hasAccessModes(MemorySegment.WRITE), !bb.isReadOnly());
460         assertTrue(segmentChecker.test(segment));
461         assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
462         assertTrue(segmentChecker.test(segment.withAccessModes(MemorySegment.READ)));
463         assertEquals(bb.capacity(), segment.byteSize());
464     }
465 
466     @Test
467     public void testRoundTripAccess() {
468         try(MemorySegment ms = MemorySegment.allocateNative(4)) {
469             MemorySegment msNoAccess = ms.withAccessModes(MemorySegment.READ); // READ is required to make BB
470             MemorySegment msRoundTrip = MemorySegment.ofByteBuffer(msNoAccess.asByteBuffer());
471             assertEquals(msNoAccess.accessModes(), msRoundTrip.accessModes());
472         }
473     }
474 
475     @Test(expectedExceptions = IllegalStateException.class)
476     public void testDeadAccessOnClosedBufferSegment() {
477         MemorySegment s1 = MemorySegment.allocateNative(MemoryLayouts.JAVA_INT);
478         MemorySegment s2 = MemorySegment.ofByteBuffer(s1.asByteBuffer());
479 
480         s1.close(); // memory freed
481 
482         intHandle.set(s2.baseAddress(), 0L, 10); // Dead access!
483     }
484 
485     @DataProvider(name = "bufferOps")
486     public static Object[][] bufferOps() throws Throwable {
487         return new Object[][]{
488                 { (Function<ByteBuffer, Buffer>) bb -> bb, bufferMembers(ByteBuffer.class)},
489                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asCharBuffer, bufferMembers(CharBuffer.class)},
490                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asShortBuffer, bufferMembers(ShortBuffer.class)},
491                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asIntBuffer, bufferMembers(IntBuffer.class)},
492                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asFloatBuffer, bufferMembers(FloatBuffer.class)},
493                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asLongBuffer, bufferMembers(LongBuffer.class)},
494                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asDoubleBuffer, bufferMembers(DoubleBuffer.class)},
495         };
496     }
497 
498     static Map<Method, Object[]> bufferMembers(Class<?> bufferClass) {
499         Map<Method, Object[]> members = new HashMap<>();
500         for (Method m : bufferClass.getMethods()) {
501             //skip statics and method declared in j.l.Object
502             if (m.getDeclaringClass().equals(Object.class) ||
503                     (m.getModifiers() & Modifier.STATIC) != 0) continue;
504             Object[] args = Stream.of(m.getParameterTypes())
505                     .map(TestByteBuffer::defaultValue)
506                     .toArray();
507             members.put(m, args);
508         }
509         return members;
510     }
511 
512     @DataProvider(name = "bufferHandleOps")
513     public static Object[][] bufferHandleOps() throws Throwable {
514         return new Object[][]{
515                 { MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) },
516                 { MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder()) },
517                 { MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.nativeOrder()) },
518                 { MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder()) },
519                 { MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.nativeOrder()) },
520                 { MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.nativeOrder()) }
521         };
522     }
523 
524     static Map<MethodHandle, Object[]> varHandleMembers(ByteBuffer bb, VarHandle handle) {
525         Map<MethodHandle, Object[]> members = new HashMap<>();
526         for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
527             Class<?>[] params = handle.accessModeType(mode).parameterArray();
528             Object[] args = Stream.concat(Stream.of(bb), Stream.of(params).skip(1)
529                     .map(TestByteBuffer::defaultValue))
530                     .toArray();
531             try {
532                 members.put(MethodHandles.varHandleInvoker(mode, handle.accessModeType(mode)), args);
533             } catch (Throwable ex) {
534                 throw new AssertionError(ex);
535             }
536         }
537         return members;
538     }
539 
540     @DataProvider(name = "resizeOps")
541     public Object[][] resizeOps() {
542         Consumer<MemoryAddress> byteInitializer =
543                 (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
544         Consumer<MemoryAddress> charInitializer =
545                 (base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
546         Consumer<MemoryAddress> shortInitializer =
547                 (base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
548         Consumer<MemoryAddress> intInitializer =
549                 (base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
550         Consumer<MemoryAddress> floatInitializer =
551                 (base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
552         Consumer<MemoryAddress> longInitializer =
553                 (base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
554         Consumer<MemoryAddress> doubleInitializer =
555                 (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
556 
557         Consumer<MemoryAddress> byteChecker =
558                 (base) -> checkBytes(base, bytes, Function.identity(), byteHandle::get, ByteBuffer::get);
559         Consumer<MemoryAddress> charChecker =
560                 (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, charHandle::get, CharBuffer::get);
561         Consumer<MemoryAddress> shortChecker =
562                 (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, shortHandle::get, ShortBuffer::get);
563         Consumer<MemoryAddress> intChecker =
564                 (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, intHandle::get, IntBuffer::get);
565         Consumer<MemoryAddress> floatChecker =
566                 (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, floatHandle::get, FloatBuffer::get);
567         Consumer<MemoryAddress> longChecker =
568                 (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, longHandle::get, LongBuffer::get);
569         Consumer<MemoryAddress> doubleChecker =
570                 (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, doubleHandle::get, DoubleBuffer::get);
571 
572         return new Object[][]{
573                 {byteChecker, byteInitializer, bytes},
574                 {charChecker, charInitializer, chars},
575                 {shortChecker, shortInitializer, shorts},
576                 {intChecker, intInitializer, ints},
577                 {floatChecker, floatInitializer, floats},
578                 {longChecker, longInitializer, longs},
579                 {doubleChecker, doubleInitializer, doubles}
580         };
581     }
582 
583     static Object defaultValue(Class<?> c) {
584         if (c.isPrimitive()) {
585             if (c == char.class) {
586                 return (char)0;
587             } else if (c == boolean.class) {
588                 return false;
589             } else if (c == byte.class) {
590                 return (byte)0;
591             } else if (c == short.class) {
592                 return (short)0;
593             } else if (c == int.class) {
594                 return 0;
595             } else if (c == long.class) {
596                 return 0L;
597             } else if (c == float.class) {
598                 return 0f;
599             } else if (c == double.class) {
600                 return 0d;
601             } else {
602                 throw new IllegalStateException();
603             }
604         } else if (c.isArray()) {
605             if (c == char[].class) {
606                 return new char[1];
607             } else if (c == boolean[].class) {
608                 return new boolean[1];
609             } else if (c == byte[].class) {
610                 return new byte[1];
611             } else if (c == short[].class) {
612                 return new short[1];
613             } else if (c == int[].class) {
614                 return new int[1];
615             } else if (c == long[].class) {
616                 return new long[1];
617             } else if (c == float[].class) {
618                 return new float[1];
619             } else if (c == double[].class) {
620                 return new double[1];
621             } else {
622                 throw new IllegalStateException();
623             }
624         } else {
625             return null;
626         }
627     }
628 
629     @DataProvider(name = "bufferSources")
630     public static Object[][] bufferSources() {
631         Predicate<MemorySegment> heapTest = segment -> segment instanceof HeapMemorySegmentImpl;
632         Predicate<MemorySegment> nativeTest = segment -> segment instanceof NativeMemorySegmentImpl;
633         Predicate<MemorySegment> mappedTest = segment -> segment instanceof MappedMemorySegmentImpl;
634         try (FileChannel channel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
635             return new Object[][]{
636                     { ByteBuffer.wrap(new byte[256]), heapTest },
637                     { ByteBuffer.allocate(256), heapTest },
638                     { ByteBuffer.allocateDirect(256), nativeTest },
639                     { channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256), mappedTest },
640 
641                     { ByteBuffer.wrap(new byte[256]).asReadOnlyBuffer(), heapTest },
642                     { ByteBuffer.allocate(256).asReadOnlyBuffer(), heapTest },
643                     { ByteBuffer.allocateDirect(256).asReadOnlyBuffer(), nativeTest },
644                     { channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256).asReadOnlyBuffer(),
645                             nativeTest /* this seems to be an existing bug in the BB implementation */ }
646             };
647         } catch (IOException ex) {
648             throw new ExceptionInInitializerError(ex);
649         }
650     }
651 }