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 import static jdk.incubator.foreign.MemorySegment.*;
  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     static final int ALL_ACCESS_MODES = READ | WRITE | CLOSE | ACQUIRE | HANDOFF;
 240 
 241     @Test
 242     public void testDefaultAccessModesMappedSegment() throws Throwable {
 243         try (MappedMemorySegment segment = MemorySegment.mapFromPath(tempPath, 8, FileChannel.MapMode.READ_WRITE)) {
 244             assertTrue(segment.hasAccessModes(ALL_ACCESS_MODES));
 245             assertEquals(segment.accessModes(), ALL_ACCESS_MODES);
 246         }
 247 
 248         try (MappedMemorySegment segment = MemorySegment.mapFromPath(tempPath, 8, FileChannel.MapMode.READ_ONLY)) {
 249             assertTrue(segment.hasAccessModes(ALL_ACCESS_MODES & ~WRITE));
 250             assertEquals(segment.accessModes(), ALL_ACCESS_MODES& ~WRITE);
 251         }
 252     }
 253 
 254     @Test
 255     public void testMappedSegment() throws Throwable {
 256         File f = new File("test2.out");
 257         f.createNewFile();
 258         f.deleteOnExit();
 259 
 260         //write to channel
 261         try (MappedMemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_WRITE)) {
 262             MemoryAddress base = segment.baseAddress();
 263             initTuples(base);
 264             segment.force();
 265         }
 266 
 267         //read from channel
 268         try (MemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_ONLY)) {
 269             MemoryAddress base = segment.baseAddress();
 270             checkTuples(base, segment.asByteBuffer());
 271         }
 272     }
 273 
 274     static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action) throws Throwable {
 275         MappedByteBuffer mbb = channel.map(mode, pos, size);
 276         var ref = new WeakReference<>(mbb);
 277         action.accept(mbb);
 278         mbb = null;
 279         //wait for it to be GCed
 280         System.gc();
 281         while (ref.get() != null) {
 282             Thread.sleep(20);
 283         }
 284     }
 285 
 286     static void checkByteArrayAlignment(MemoryLayout layout) {
 287         if (layout.bitSize() > 32
 288                 && System.getProperty("sun.arch.data.model").equals("32")) {
 289             throw new SkipException("avoid unaligned access on 32-bit system");
 290         }
 291     }
 292 
 293     @Test(dataProvider = "bufferOps")
 294     public void testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
 295         Buffer bb;
 296         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
 297             MemoryAddress base = segment.baseAddress();
 298             bb = bufferFactory.apply(segment.asByteBuffer());
 299         }
 300         //outside of scope!!
 301         for (Map.Entry<Method, Object[]> e : members.entrySet()) {
 302             if (!e.getKey().getName().contains("get") &&
 303                             !e.getKey().getName().contains("put")) {
 304                 //skip
 305                 return;
 306             }
 307             try {
 308                 e.getKey().invoke(bb, e.getValue());
 309                 assertTrue(false);
 310             } catch (InvocationTargetException ex) {
 311                 Throwable cause = ex.getCause();
 312                 if (cause instanceof IllegalStateException) {
 313                     //all get/set buffer operation should fail because of the scope check
 314                     assertTrue(ex.getCause().getMessage().contains("not alive"));
 315                 } else {
 316                     //all other exceptions were unexpected - fail
 317                     assertTrue(false);
 318                 }
 319             } catch (Throwable ex) {
 320                 //unexpected exception - fail
 321                 assertTrue(false);
 322             }
 323         }
 324     }
 325 
 326     @Test(dataProvider = "bufferHandleOps")
 327     public void testScopedBufferAndVarHandle(VarHandle bufferHandle) {
 328         ByteBuffer bb;
 329         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
 330             bb = segment.asByteBuffer();
 331             for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
 332                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
 333                         .asSpreader(Object[].class, e.getValue().length);
 334                 try {
 335                     handle.invoke(e.getValue());
 336                 } catch (UnsupportedOperationException ex) {
 337                     //skip
 338                 } catch (Throwable ex) {
 339                     //should not fail - segment is alive!
 340                     fail();
 341                 }
 342             }
 343         }
 344         for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
 345             try {
 346                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
 347                         .asSpreader(Object[].class, e.getValue().length);
 348                 handle.invoke(e.getValue());
 349                 fail();
 350             } catch (IllegalStateException ex) {
 351                 assertTrue(ex.getMessage().contains("not alive"));
 352             } catch (UnsupportedOperationException ex) {
 353                 //skip
 354             } catch (Throwable ex) {
 355                 fail();
 356             }
 357         }
 358     }
 359 
 360     @Test(dataProvider = "bufferOps")
 361     public void testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
 362         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
 363             MemoryAddress base = segment.baseAddress();
 364             Buffer bb = bufferFactory.apply(segment.asByteBuffer());
 365             assertTrue(bb.isDirect());
 366             DirectBuffer directBuffer = ((DirectBuffer)bb);
 367             assertEquals(directBuffer.address(), ((MemoryAddressImpl)base).unsafeGetOffset());
 368             assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer));
 369             assertTrue(directBuffer.cleaner() == null);
 370         }
 371     }
 372 
 373     @Test(dataProvider="resizeOps")
 374     public void testResizeOffheap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 375         try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
 376             MemoryAddress base = segment.baseAddress();
 377             initializer.accept(base);
 378             checker.accept(base);
 379         }
 380     }
 381 
 382     @Test(dataProvider="resizeOps")
 383     public void testResizeHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 384         checkByteArrayAlignment(seq.elementLayout());
 385         int capacity = (int)seq.byteSize();
 386         MemoryAddress base = MemorySegment.ofArray(new byte[capacity]).baseAddress();
 387         initializer.accept(base);
 388         checker.accept(base);
 389     }
 390 
 391     @Test(dataProvider="resizeOps")
 392     public void testResizeBuffer(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 393         checkByteArrayAlignment(seq.elementLayout());
 394         int capacity = (int)seq.byteSize();
 395         MemoryAddress base = MemorySegment.ofByteBuffer(ByteBuffer.wrap(new byte[capacity])).baseAddress();
 396         initializer.accept(base);
 397         checker.accept(base);
 398     }
 399 
 400     @Test(dataProvider="resizeOps")
 401     public void testResizeRoundtripHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 402         checkByteArrayAlignment(seq.elementLayout());
 403         int capacity = (int)seq.byteSize();
 404         byte[] arr = new byte[capacity];
 405         MemorySegment segment = MemorySegment.ofArray(arr);
 406         MemoryAddress first = segment.baseAddress();
 407         initializer.accept(first);
 408         MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
 409         checker.accept(second);
 410     }
 411 
 412     @Test(dataProvider="resizeOps")
 413     public void testResizeRoundtripNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 414         try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
 415             MemoryAddress first = segment.baseAddress();
 416             initializer.accept(first);
 417             MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
 418             checker.accept(second);
 419         }
 420     }
 421 
 422     @Test(expectedExceptions = IllegalStateException.class)
 423     public void testBufferOnClosedScope() {
 424         MemorySegment leaked;
 425         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
 426             leaked = segment;
 427         }
 428         ByteBuffer byteBuffer = leaked.asByteBuffer(); // ok
 429         byteBuffer.get(); // should throw
 430     }
 431 
 432     @Test(expectedExceptions = { UnsupportedOperationException.class,
 433                                  IllegalArgumentException.class })
 434     public void testTooBigForByteBuffer() {
 435         try (MemorySegment segment = MemorySegment.allocateNative((long)Integer.MAX_VALUE + 10L)) {
 436             segment.asByteBuffer();
 437         }
 438     }
 439 
 440     @Test(dataProvider="resizeOps")
 441     public void testCopyHeapToNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 442         checkByteArrayAlignment(seq.elementLayout());
 443         int bytes = (int)seq.byteSize();
 444         try (MemorySegment nativeArray = MemorySegment.allocateNative(bytes);
 445              MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
 446             initializer.accept(heapArray.baseAddress());
 447             MemoryAddress.copy(heapArray.baseAddress(), nativeArray.baseAddress(), bytes);
 448             checker.accept(nativeArray.baseAddress());
 449         }
 450     }
 451 
 452     @Test(dataProvider="resizeOps")
 453     public void testCopyNativeToHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
 454         checkByteArrayAlignment(seq.elementLayout());
 455         int bytes = (int)seq.byteSize();
 456         try (MemorySegment nativeArray = MemorySegment.allocateNative(seq);
 457              MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
 458             initializer.accept(nativeArray.baseAddress());
 459             MemoryAddress.copy(nativeArray.baseAddress(), heapArray.baseAddress(), bytes);
 460             checker.accept(heapArray.baseAddress());
 461         }
 462     }
 463 
 464     @Test
 465     public void testDefaultAccessModesOfBuffer() {
 466         ByteBuffer rwBuffer = ByteBuffer.wrap(new byte[4]);
 467         try (MemorySegment segment = MemorySegment.ofByteBuffer(rwBuffer)) {
 468             assertTrue(segment.hasAccessModes(ALL_ACCESS_MODES));
 469             assertEquals(segment.accessModes(), ALL_ACCESS_MODES);
 470         }
 471 
 472         ByteBuffer roBuffer = rwBuffer.asReadOnlyBuffer();
 473         try (MemorySegment segment = MemorySegment.ofByteBuffer(roBuffer)) {
 474             assertTrue(segment.hasAccessModes(ALL_ACCESS_MODES & ~WRITE));
 475             assertEquals(segment.accessModes(), ALL_ACCESS_MODES & ~WRITE);
 476         }
 477     }
 478 
 479     @Test(dataProvider="bufferSources")
 480     public void testBufferToSegment(ByteBuffer bb, Predicate<MemorySegment> segmentChecker) {
 481         MemorySegment segment = MemorySegment.ofByteBuffer(bb);
 482         assertEquals(segment.hasAccessModes(MemorySegment.WRITE), !bb.isReadOnly());
 483         assertTrue(segmentChecker.test(segment));
 484         assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
 485         assertTrue(segmentChecker.test(segment.withAccessModes(MemorySegment.READ)));
 486         assertEquals(bb.capacity(), segment.byteSize());
 487         //another round trip
 488         segment = MemorySegment.ofByteBuffer(segment.asByteBuffer());
 489         assertEquals(segment.hasAccessModes(MemorySegment.WRITE), !bb.isReadOnly());
 490         assertTrue(segmentChecker.test(segment));
 491         assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
 492         assertTrue(segmentChecker.test(segment.withAccessModes(MemorySegment.READ)));
 493         assertEquals(bb.capacity(), segment.byteSize());
 494     }
 495 
 496     @Test
 497     public void testRoundTripAccess() {
 498         try(MemorySegment ms = MemorySegment.allocateNative(4)) {
 499             MemorySegment msNoAccess = ms.withAccessModes(MemorySegment.READ); // READ is required to make BB
 500             MemorySegment msRoundTrip = MemorySegment.ofByteBuffer(msNoAccess.asByteBuffer());
 501             assertEquals(msNoAccess.accessModes(), msRoundTrip.accessModes());
 502         }
 503     }
 504 
 505     @Test(expectedExceptions = IllegalStateException.class)
 506     public void testDeadAccessOnClosedBufferSegment() {
 507         MemorySegment s1 = MemorySegment.allocateNative(MemoryLayouts.JAVA_INT);
 508         MemorySegment s2 = MemorySegment.ofByteBuffer(s1.asByteBuffer());
 509 
 510         s1.close(); // memory freed
 511 
 512         intHandle.set(s2.baseAddress(), 0L, 10); // Dead access!
 513     }
 514 
 515     @DataProvider(name = "bufferOps")
 516     public static Object[][] bufferOps() throws Throwable {
 517         return new Object[][]{
 518                 { (Function<ByteBuffer, Buffer>) bb -> bb, bufferMembers(ByteBuffer.class)},
 519                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asCharBuffer, bufferMembers(CharBuffer.class)},
 520                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asShortBuffer, bufferMembers(ShortBuffer.class)},
 521                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asIntBuffer, bufferMembers(IntBuffer.class)},
 522                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asFloatBuffer, bufferMembers(FloatBuffer.class)},
 523                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asLongBuffer, bufferMembers(LongBuffer.class)},
 524                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asDoubleBuffer, bufferMembers(DoubleBuffer.class)},
 525         };
 526     }
 527 
 528     static Map<Method, Object[]> bufferMembers(Class<?> bufferClass) {
 529         Map<Method, Object[]> members = new HashMap<>();
 530         for (Method m : bufferClass.getMethods()) {
 531             //skip statics and method declared in j.l.Object
 532             if (m.getDeclaringClass().equals(Object.class) ||
 533                     (m.getModifiers() & Modifier.STATIC) != 0) continue;
 534             Object[] args = Stream.of(m.getParameterTypes())
 535                     .map(TestByteBuffer::defaultValue)
 536                     .toArray();
 537             members.put(m, args);
 538         }
 539         return members;
 540     }
 541 
 542     @DataProvider(name = "bufferHandleOps")
 543     public static Object[][] bufferHandleOps() throws Throwable {
 544         return new Object[][]{
 545                 { MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) },
 546                 { MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder()) },
 547                 { MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.nativeOrder()) },
 548                 { MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder()) },
 549                 { MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.nativeOrder()) },
 550                 { MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.nativeOrder()) }
 551         };
 552     }
 553 
 554     static Map<MethodHandle, Object[]> varHandleMembers(ByteBuffer bb, VarHandle handle) {
 555         Map<MethodHandle, Object[]> members = new HashMap<>();
 556         for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
 557             Class<?>[] params = handle.accessModeType(mode).parameterArray();
 558             Object[] args = Stream.concat(Stream.of(bb), Stream.of(params).skip(1)
 559                     .map(TestByteBuffer::defaultValue))
 560                     .toArray();
 561             try {
 562                 members.put(MethodHandles.varHandleInvoker(mode, handle.accessModeType(mode)), args);
 563             } catch (Throwable ex) {
 564                 throw new AssertionError(ex);
 565             }
 566         }
 567         return members;
 568     }
 569 
 570     @DataProvider(name = "resizeOps")
 571     public Object[][] resizeOps() {
 572         Consumer<MemoryAddress> byteInitializer =
 573                 (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
 574         Consumer<MemoryAddress> charInitializer =
 575                 (base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
 576         Consumer<MemoryAddress> shortInitializer =
 577                 (base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
 578         Consumer<MemoryAddress> intInitializer =
 579                 (base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
 580         Consumer<MemoryAddress> floatInitializer =
 581                 (base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
 582         Consumer<MemoryAddress> longInitializer =
 583                 (base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
 584         Consumer<MemoryAddress> doubleInitializer =
 585                 (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
 586 
 587         Consumer<MemoryAddress> byteChecker =
 588                 (base) -> checkBytes(base, bytes, Function.identity(), byteHandle::get, ByteBuffer::get);
 589         Consumer<MemoryAddress> charChecker =
 590                 (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, charHandle::get, CharBuffer::get);
 591         Consumer<MemoryAddress> shortChecker =
 592                 (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, shortHandle::get, ShortBuffer::get);
 593         Consumer<MemoryAddress> intChecker =
 594                 (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, intHandle::get, IntBuffer::get);
 595         Consumer<MemoryAddress> floatChecker =
 596                 (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, floatHandle::get, FloatBuffer::get);
 597         Consumer<MemoryAddress> longChecker =
 598                 (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, longHandle::get, LongBuffer::get);
 599         Consumer<MemoryAddress> doubleChecker =
 600                 (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, doubleHandle::get, DoubleBuffer::get);
 601 
 602         return new Object[][]{
 603                 {byteChecker, byteInitializer, bytes},
 604                 {charChecker, charInitializer, chars},
 605                 {shortChecker, shortInitializer, shorts},
 606                 {intChecker, intInitializer, ints},
 607                 {floatChecker, floatInitializer, floats},
 608                 {longChecker, longInitializer, longs},
 609                 {doubleChecker, doubleInitializer, doubles}
 610         };
 611     }
 612 
 613     static Object defaultValue(Class<?> c) {
 614         if (c.isPrimitive()) {
 615             if (c == char.class) {
 616                 return (char)0;
 617             } else if (c == boolean.class) {
 618                 return false;
 619             } else if (c == byte.class) {
 620                 return (byte)0;
 621             } else if (c == short.class) {
 622                 return (short)0;
 623             } else if (c == int.class) {
 624                 return 0;
 625             } else if (c == long.class) {
 626                 return 0L;
 627             } else if (c == float.class) {
 628                 return 0f;
 629             } else if (c == double.class) {
 630                 return 0d;
 631             } else {
 632                 throw new IllegalStateException();
 633             }
 634         } else if (c.isArray()) {
 635             if (c == char[].class) {
 636                 return new char[1];
 637             } else if (c == boolean[].class) {
 638                 return new boolean[1];
 639             } else if (c == byte[].class) {
 640                 return new byte[1];
 641             } else if (c == short[].class) {
 642                 return new short[1];
 643             } else if (c == int[].class) {
 644                 return new int[1];
 645             } else if (c == long[].class) {
 646                 return new long[1];
 647             } else if (c == float[].class) {
 648                 return new float[1];
 649             } else if (c == double[].class) {
 650                 return new double[1];
 651             } else {
 652                 throw new IllegalStateException();
 653             }
 654         } else {
 655             return null;
 656         }
 657     }
 658 
 659     @DataProvider(name = "bufferSources")
 660     public static Object[][] bufferSources() {
 661         Predicate<MemorySegment> heapTest = segment -> segment instanceof HeapMemorySegmentImpl;
 662         Predicate<MemorySegment> nativeTest = segment -> segment instanceof NativeMemorySegmentImpl;
 663         Predicate<MemorySegment> mappedTest = segment -> segment instanceof MappedMemorySegmentImpl;
 664         try (FileChannel channel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 665             return new Object[][]{
 666                     { ByteBuffer.wrap(new byte[256]), heapTest },
 667                     { ByteBuffer.allocate(256), heapTest },
 668                     { ByteBuffer.allocateDirect(256), nativeTest },
 669                     { channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256), mappedTest },
 670 
 671                     { ByteBuffer.wrap(new byte[256]).asReadOnlyBuffer(), heapTest },
 672                     { ByteBuffer.allocate(256).asReadOnlyBuffer(), heapTest },
 673                     { ByteBuffer.allocateDirect(256).asReadOnlyBuffer(), nativeTest },
 674                     { channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256).asReadOnlyBuffer(),
 675                             nativeTest /* this seems to be an existing bug in the BB implementation */ }
 676             };
 677         } catch (IOException ex) {
 678             throw new ExceptionInInitializerError(ex);
 679         }
 680     }
 681 }