1 /*
   2  * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @modules java.base/sun.nio.ch java.base/jdk.internal.foreign
  27  * @run testng/othervm/timeout=600 --enable-native-access=ALL-UNNAMED TestByteBuffer
  28  */
  29 
  30 import java.lang.foreign.*;
  31 import java.lang.foreign.MemoryLayout.PathElement;
  32 
  33 import java.io.File;
  34 import java.io.IOException;
  35 import java.lang.invoke.MethodHandle;
  36 import java.lang.invoke.MethodHandles;
  37 import java.lang.invoke.VarHandle;
  38 import java.lang.ref.Cleaner;
  39 import java.lang.ref.Reference;
  40 import java.lang.ref.WeakReference;
  41 import java.lang.reflect.InvocationTargetException;
  42 import java.lang.reflect.Method;
  43 import java.lang.reflect.Modifier;
  44 import java.net.URI;
  45 import java.nio.Buffer;
  46 import java.nio.ByteBuffer;
  47 import java.nio.ByteOrder;
  48 import java.nio.CharBuffer;
  49 import java.nio.DoubleBuffer;
  50 import java.nio.FloatBuffer;
  51 import java.nio.IntBuffer;
  52 import java.nio.LongBuffer;
  53 import java.nio.MappedByteBuffer;
  54 import java.nio.ShortBuffer;
  55 import java.nio.channels.FileChannel;
  56 import java.nio.file.Files;
  57 import java.nio.file.Path;
  58 import java.nio.file.StandardOpenOption;
  59 import java.util.ArrayList;
  60 import java.util.HashMap;
  61 import java.util.List;
  62 import java.util.Map;
  63 import java.util.concurrent.atomic.AtomicBoolean;
  64 import java.util.function.BiConsumer;
  65 import java.util.function.BiFunction;
  66 import java.util.function.Consumer;
  67 import java.util.function.Function;
  68 import java.util.function.Predicate;
  69 import java.util.function.Supplier;
  70 import java.util.stream.Stream;
  71 
  72 import jdk.internal.foreign.HeapMemorySegmentImpl;
  73 import jdk.internal.foreign.MappedMemorySegmentImpl;
  74 import jdk.internal.foreign.NativeMemorySegmentImpl;
  75 import org.testng.SkipException;
  76 import org.testng.annotations.*;
  77 import sun.nio.ch.DirectBuffer;
  78 
  79 import static java.lang.foreign.ValueLayout.*;
  80 import static org.testng.Assert.*;
  81 
  82 public class TestByteBuffer {
  83 
  84     static final Path tempPath;
  85 
  86     static {
  87         try {
  88             File file = File.createTempFile("buffer", "txt");
  89             file.deleteOnExit();
  90             tempPath = file.toPath();
  91             Files.write(file.toPath(), new byte[256], StandardOpenOption.WRITE);
  92 
  93         } catch (IOException ex) {
  94             throw new ExceptionInInitializerError(ex);
  95         }
  96     }
  97 
  98     static final ValueLayout.OfChar BB_CHAR = JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
  99     static final ValueLayout.OfShort BB_SHORT = JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
 100     static final ValueLayout.OfInt BB_INT = JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
 101     static final ValueLayout.OfLong BB_LONG = JAVA_LONG_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
 102     static final ValueLayout.OfFloat BB_FLOAT = JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
 103     static final ValueLayout.OfDouble BB_DOUBLE = JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
 104 
 105     static SequenceLayout tuples = MemoryLayout.sequenceLayout(500,
 106             MemoryLayout.structLayout(
 107                     BB_INT.withName("index"),
 108                     BB_FLOAT.withName("value")
 109             ));
 110 
 111     static final SequenceLayout bytes = MemoryLayout.sequenceLayout(100, JAVA_BYTE);
 112     static final SequenceLayout chars = MemoryLayout.sequenceLayout(100, BB_CHAR);
 113     static final SequenceLayout shorts = MemoryLayout.sequenceLayout(100, BB_SHORT);
 114     static final SequenceLayout ints = MemoryLayout.sequenceLayout(100, BB_INT);
 115     static final SequenceLayout floats = MemoryLayout.sequenceLayout(100, BB_FLOAT);
 116     static final SequenceLayout longs = MemoryLayout.sequenceLayout(100, BB_LONG);
 117     static final SequenceLayout doubles = MemoryLayout.sequenceLayout(100, BB_DOUBLE);
 118 
 119     static final VarHandle indexHandle = tuples.varHandle(PathElement.sequenceElement(), PathElement.groupElement("index"));
 120     static final VarHandle valueHandle = tuples.varHandle(PathElement.sequenceElement(), PathElement.groupElement("value"));
 121 
 122     static void initTuples(MemorySegment base, long count) {
 123         for (long i = 0; i < count ; i++) {
 124             indexHandle.set(base, 0L, i, (int)i);
 125             valueHandle.set(base, 0L, i, (float)(i / 500f));
 126         }
 127     }
 128 
 129     static void checkTuples(MemorySegment base, ByteBuffer bb, long count) {
 130         for (long i = 0; i < count ; i++) {
 131             int index;
 132             float value;
 133             assertEquals(index = bb.getInt(), (int)indexHandle.get(base, 0L, i));
 134             assertEquals(value = bb.getFloat(), (float)valueHandle.get(base, 0L, i));
 135             assertEquals(value, index / 500f);
 136         }
 137     }
 138 
 139     static void initBytes(MemorySegment base, SequenceLayout seq, BiConsumer<MemorySegment, Long> handleSetter) {
 140         for (long i = 0; i < seq.elementCount() ; i++) {
 141             handleSetter.accept(base, i);
 142         }
 143     }
 144 
 145     static <Z extends Buffer> void checkBytes(MemorySegment base, SequenceLayout layout,
 146                                               Function<ByteBuffer, Z> bufFactory,
 147                                               BiFunction<MemorySegment, Long, Object> handleExtractor,
 148                                               Function<Z, Object> bufferExtractor) {
 149         long nelems = layout.elementCount();
 150         long elemSize = layout.elementLayout().byteSize();
 151         for (long i = 0 ; i < nelems ; i++) {
 152             long limit = nelems - i;
 153             MemorySegment resizedSegment = base.asSlice(i * elemSize, limit * elemSize);
 154             ByteBuffer bb = resizedSegment.asByteBuffer();
 155             Z z = bufFactory.apply(bb);
 156             MemorySegment segmentBufferView = MemorySegment.ofBuffer(z);
 157             for (long j = i ; j < limit ; j++) {
 158                 Object handleValue = handleExtractor.apply(resizedSegment, j - i);
 159                 Object bufferValue = bufferExtractor.apply(z);
 160                 Object handleViewValue = handleExtractor.apply(segmentBufferView, j - i);
 161                 if (handleValue instanceof Number) {
 162                     assertEquals(((Number)handleValue).longValue(), j);
 163                     assertEquals(((Number)bufferValue).longValue(), j);
 164                     assertEquals(((Number)handleViewValue).longValue(), j);
 165                 } else {
 166                     assertEquals((long)(char)handleValue, j);
 167                     assertEquals((long)(char)bufferValue, j);
 168                     assertEquals((long)(char)handleViewValue, j);
 169                 }
 170             }
 171         }
 172     }
 173 
 174     @Test
 175     public void testOffheap() {
 176         try (Arena arena = Arena.ofConfined()) {
 177             MemorySegment segment = arena.allocate(tuples);;
 178             initTuples(segment, tuples.elementCount());
 179 
 180             ByteBuffer bb = segment.asByteBuffer();
 181             checkTuples(segment, bb, tuples.elementCount());
 182         }
 183     }
 184 
 185     @Test
 186     public void testHeap() {
 187         byte[] arr = new byte[(int) tuples.byteSize()];
 188         MemorySegment region = MemorySegment.ofArray(arr);
 189         initTuples(region, tuples.elementCount());
 190 
 191         ByteBuffer bb = region.asByteBuffer();
 192         checkTuples(region, bb, tuples.elementCount());
 193     }
 194 
 195     @Test
 196     public void testChannel() throws Throwable {
 197         File f = new File("test.out");
 198         assertTrue(f.createNewFile());
 199         f.deleteOnExit();
 200 
 201         //write to channel
 202         try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 203             withMappedBuffer(channel, FileChannel.MapMode.READ_WRITE, 0, tuples.byteSize(), mbb -> {
 204                 MemorySegment segment = MemorySegment.ofBuffer(mbb);
 205                 initTuples(segment, tuples.elementCount());
 206                 mbb.force();
 207             });
 208         }
 209 
 210         //read from channel
 211         try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
 212             withMappedBuffer(channel, FileChannel.MapMode.READ_ONLY, 0, tuples.byteSize(), mbb -> {
 213                 MemorySegment segment = MemorySegment.ofBuffer(mbb);
 214                 checkTuples(segment, mbb, tuples.elementCount());
 215             });
 216         }
 217     }
 218 
 219     @Test
 220     public void testDefaultAccessModesMappedSegment() throws Throwable {
 221         try (Arena arena = Arena.ofConfined();
 222              FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 223             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 8L, arena);
 224             assertFalse(segment.isReadOnly());
 225         }
 226 
 227         try (Arena arena = Arena.ofConfined();
 228              FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ)) {
 229             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, 8L, arena);
 230             assertTrue(segment.isReadOnly());
 231         }
 232     }
 233 
 234     @Test
 235     public void testMappedSegment() throws Throwable {
 236         File f = new File("test2.out");
 237         f.createNewFile();
 238         f.deleteOnExit();
 239 
 240         try (Arena arena = Arena.ofConfined();
 241              FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 242             //write to channel
 243             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, tuples.byteSize(), arena);
 244             initTuples(segment, tuples.elementCount());
 245             segment.force();
 246         }
 247 
 248         try (Arena arena = Arena.ofConfined();
 249              FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
 250             //read from channel
 251             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, tuples.byteSize(), arena);
 252             checkTuples(segment, segment.asByteBuffer(), tuples.elementCount());
 253         }
 254     }
 255 
 256     @Test(dataProvider = "mappedOps", expectedExceptions = IllegalStateException.class)
 257     public void testMappedSegmentOperations(MappedSegmentOp mappedBufferOp) throws Throwable {
 258         File f = new File("test3.out");
 259         f.createNewFile();
 260         f.deleteOnExit();
 261 
 262         Arena arena = Arena.ofConfined();
 263         try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 264             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 8L, arena);
 265             assertTrue(segment.isMapped());
 266             arena.close();
 267             mappedBufferOp.apply(segment);
 268         }
 269     }
 270 
 271     @Test
 272     public void testMappedSegmentOffset() throws Throwable {
 273         File f = new File("test3.out");
 274         f.createNewFile();
 275         f.deleteOnExit();
 276 
 277         MemoryLayout tupleLayout = tuples.elementLayout();
 278 
 279         // write one at a time
 280         for (int i = 0 ; i < tuples.byteSize() ; i += tupleLayout.byteSize()) {
 281             try (Arena arena = Arena.ofConfined();
 282                  FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 283                 //write to channel
 284                 MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, i, tuples.byteSize(), arena);
 285                 initTuples(segment, 1);
 286                 segment.force();
 287             }
 288         }
 289 
 290         // check one at a time
 291         for (int i = 0 ; i < tuples.byteSize() ; i += tupleLayout.byteSize()) {
 292             try (Arena arena = Arena.ofConfined();
 293                  FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
 294                 //read from channel
 295                 MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, tuples.byteSize(), arena);
 296                 checkTuples(segment, segment.asByteBuffer(), 1);
 297             }
 298         }
 299     }
 300 
 301     @Test(dataProvider = "fromArrays")
 302     public void testAsByteBufferFromNonByteArray(MemorySegment segment) {
 303         if (!segment.heapBase().map(a -> a instanceof byte[]).get()) {
 304             // This should not work as the segment is not backed by a byte array
 305             assertThrows(UnsupportedOperationException.class, segment::asByteBuffer);
 306         }
 307     }
 308 
 309     @Test
 310     public void testMappedSegmentAsByteBuffer() throws Throwable {
 311         File f = new File("test4.out");
 312         assertTrue(f.createNewFile());
 313         f.deleteOnExit();
 314 
 315         for (var mapOption : List.of(FileChannel.MapMode.READ_WRITE, FileChannel.MapMode.READ_ONLY, FileChannel.MapMode.PRIVATE)) {
 316             for (var arena : List.of(Arena.ofConfined(), Arena.global())) {
 317                 try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 318                     //write to channel
 319                     MemorySegment segment = fileChannel.map(mapOption, 0L, 32L, arena);
 320                     segment.force();
 321                     segment.load();
 322                     segment.isLoaded();
 323                     segment.unload();
 324                     ByteBuffer byteBuffer = segment.asByteBuffer();
 325                     assertEquals(byteBuffer.capacity(), segment.byteSize());
 326                     assertEquals(byteBuffer.isReadOnly(), segment.isReadOnly());
 327                     assertTrue(byteBuffer.isDirect());
 328                 } catch (IOException e) {
 329                     if (e.getMessage().equals("Function not implemented"))
 330                         throw new SkipException(e.getMessage(), e);
 331                 } finally {
 332                     if (arena.scope() != Arena.global().scope()) {
 333                         arena.close();
 334                     }
 335                 }
 336             }
 337         }
 338     }
 339 
 340     static final long LARGE_SIZE = (2L * 1024L + 512L) * 1024L * 1024L; // 2.5 GiB
 341 
 342     @Test
 343     public void testLargeMappedSegment() throws Throwable {
 344         if (System.getProperty("sun.arch.data.model").equals("32")) {
 345             throw new SkipException("large mapped files not supported on 32-bit systems");
 346         }
 347 
 348         File f = new File("testLargeMappedSegment.out");
 349         f.createNewFile();
 350         f.deleteOnExit();
 351 
 352         try (Arena arena = Arena.ofConfined();
 353              FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 354             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, LARGE_SIZE, arena);
 355             segment.isLoaded();
 356             segment.load();
 357             segment.isLoaded();
 358             segment.force();
 359             segment.isLoaded();
 360             segment.unload();
 361             segment.isLoaded();
 362         } catch(IOException e) {
 363             if (e.getMessage().equals("Function not implemented"))
 364                 throw new SkipException(e.getMessage(), e);
 365         }
 366     }
 367 
 368     static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action) throws Throwable {
 369         MappedByteBuffer mbb = channel.map(mode, pos, size);
 370         var ref = new WeakReference<>(mbb);
 371         action.accept(mbb);
 372         mbb = null;
 373         //wait for it to be GCed
 374         System.gc();
 375         while (ref.get() != null) {
 376             Thread.sleep(20);
 377         }
 378     }
 379 
 380     static void checkByteArrayAlignment(MemoryLayout layout) {
 381         if (layout.byteSize() > 4
 382                 && System.getProperty("sun.arch.data.model").equals("32")) {
 383             throw new SkipException("avoid unaligned access on 32-bit system");
 384         }
 385     }
 386 
 387     @Test(dataProvider = "bufferOps")
 388     public void testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, @NoInjection Method method, Object[] args) {
 389         Buffer bb;
 390         try (Arena arena = Arena.ofConfined()) {
 391             MemorySegment segment = arena.allocate(bytes);;
 392             bb = bufferFactory.apply(segment.asByteBuffer());
 393         }
 394         //outside of session!!
 395         try {
 396             method.invoke(bb, args);
 397             fail("Exception expected");
 398         } catch (InvocationTargetException ex) {
 399             Throwable cause = ex.getCause();
 400             if (cause instanceof IllegalStateException) {
 401                 //all get/set buffer operation should fail because of the session check
 402                 assertTrue(ex.getCause().getMessage().contains("Already closed"));
 403             } else {
 404                 //all other exceptions were unexpected - fail
 405                 fail("Unexpected exception", cause);
 406             }
 407         } catch (Throwable ex) {
 408             //unexpected exception - fail
 409             fail("Unexpected exception", ex);
 410         }
 411     }
 412 
 413     @Test(dataProvider = "bufferHandleOps")
 414     public void testScopedBufferAndVarHandle(VarHandle bufferHandle) {
 415         ByteBuffer bb;
 416         try (Arena arena = Arena.ofConfined()) {
 417             MemorySegment segment = arena.allocate(bytes);;
 418             bb = segment.asByteBuffer();
 419             for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
 420                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
 421                         .asSpreader(Object[].class, e.getValue().length);
 422                 try {
 423                     handle.invoke(e.getValue());
 424                 } catch (UnsupportedOperationException ex) {
 425                     //skip
 426                 } catch (Throwable ex) {
 427                     //should not fail - segment is alive!
 428                     fail();
 429                 }
 430             }
 431         }
 432         for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
 433             try {
 434                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
 435                         .asSpreader(Object[].class, e.getValue().length);
 436                 handle.invoke(e.getValue());
 437                 fail();
 438             } catch (IllegalStateException ex) {
 439                 assertTrue(ex.getMessage().contains("Already closed"));
 440             } catch (UnsupportedOperationException ex) {
 441                 //skip
 442             } catch (Throwable ex) {
 443                 fail();
 444             }
 445         }
 446     }
 447 
 448     @Test(dataProvider = "bufferOps")
 449     public void testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, @NoInjection Method method, Object[] args) {
 450         try (Arena arena = Arena.ofConfined()) {
 451             MemorySegment segment = arena.allocate(bytes);;
 452             Buffer bb = bufferFactory.apply(segment.asByteBuffer());
 453             assertTrue(bb.isDirect());
 454             DirectBuffer directBuffer = ((DirectBuffer)bb);
 455             assertEquals(directBuffer.address(), segment.address());
 456             assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer));
 457             assertTrue(directBuffer.cleaner() == null);
 458         }
 459     }
 460 
 461     @Test(dataProvider="resizeOps")
 462     public void testResizeOffheap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 463         try (Arena arena = Arena.ofConfined()) {
 464             MemorySegment segment = arena.allocate(seq);;
 465             initializer.accept(segment);
 466             checker.accept(segment);
 467         }
 468     }
 469 
 470     @Test(dataProvider="resizeOps")
 471     public void testResizeHeap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 472         checkByteArrayAlignment(seq.elementLayout());
 473         int capacity = (int)seq.byteSize();
 474         MemorySegment base = MemorySegment.ofArray(new byte[capacity]);
 475         initializer.accept(base);
 476         checker.accept(base);
 477     }
 478 
 479     @Test(dataProvider="resizeOps")
 480     public void testResizeBuffer(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 481         checkByteArrayAlignment(seq.elementLayout());
 482         int capacity = (int)seq.byteSize();
 483         MemorySegment base = MemorySegment.ofBuffer(ByteBuffer.wrap(new byte[capacity]));
 484         initializer.accept(base);
 485         checker.accept(base);
 486     }
 487 
 488     @Test(dataProvider="resizeOps")
 489     public void testResizeRoundtripHeap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 490         checkByteArrayAlignment(seq.elementLayout());
 491         int capacity = (int)seq.byteSize();
 492         byte[] arr = new byte[capacity];
 493         MemorySegment segment = MemorySegment.ofArray(arr);
 494         initializer.accept(segment);
 495         MemorySegment second = MemorySegment.ofBuffer(segment.asByteBuffer());
 496         checker.accept(second);
 497     }
 498 
 499     @Test(dataProvider="resizeOps")
 500     public void testResizeRoundtripNative(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 501         try (Arena arena = Arena.ofConfined()) {
 502             MemorySegment segment = arena.allocate(seq);;
 503             initializer.accept(segment);
 504             MemorySegment second = MemorySegment.ofBuffer(segment.asByteBuffer());
 505             checker.accept(second);
 506         }
 507     }
 508 
 509     @Test(expectedExceptions = IllegalStateException.class)
 510     public void testBufferOnClosedSession() {
 511         MemorySegment leaked;
 512         try (Arena arena = Arena.ofConfined()) {
 513             leaked = arena.allocate(bytes);;
 514         }
 515         ByteBuffer byteBuffer = leaked.asByteBuffer(); // ok
 516         byteBuffer.get(); // should throw
 517     }
 518 
 519     @Test(expectedExceptions = IllegalStateException.class)
 520     public void testTooBigForByteBuffer() {
 521         MemorySegment segment = MemorySegment.NULL.reinterpret(Integer.MAX_VALUE + 10L);
 522         segment.asByteBuffer();
 523     }
 524 
 525     @Test(expectedExceptions = IllegalArgumentException.class)
 526     public void testBadMapNegativeSize() throws IOException {
 527         File f = new File("testNeg1.out");
 528         f.createNewFile();
 529         f.deleteOnExit();
 530         try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 531             fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, -1L, Arena.ofAuto());
 532         }
 533     }
 534 
 535     @Test(expectedExceptions = IllegalArgumentException.class)
 536     public void testBadMapNegativeOffset() throws IOException {
 537         File f = new File("testNeg2.out");
 538         f.createNewFile();
 539         f.deleteOnExit();
 540         try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 541             fileChannel.map(FileChannel.MapMode.READ_WRITE, -1L, 1L, Arena.ofAuto());
 542         }
 543     }
 544 
 545     @Test
 546     public void testMapOffset() throws IOException {
 547         File f = new File("testMapOffset.out");
 548         f.createNewFile();
 549         f.deleteOnExit();
 550 
 551         int SIZE = Byte.MAX_VALUE;
 552 
 553         try (Arena arena = Arena.ofConfined();
 554              FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 555             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, SIZE, arena);
 556             for (byte offset = 0; offset < SIZE; offset++) {
 557                 segment.set(JAVA_BYTE, offset, offset);
 558             }
 559             segment.force();
 560         }
 561 
 562         for (int offset = 0 ; offset < SIZE ; offset++) {
 563             try (Arena arena = Arena.ofConfined();
 564                  FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
 565                 MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, offset, SIZE - offset, arena);
 566                 assertEquals(segment.get(JAVA_BYTE, 0), offset);
 567             }
 568         }
 569     }
 570 
 571     @Test
 572     public void testMapZeroSize() throws IOException {
 573         File f = new File("testPos1.out");
 574         f.createNewFile();
 575         f.deleteOnExit();
 576         //RW
 577         try (Arena arena = Arena.ofConfined();
 578              FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 579             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 0L, arena);
 580             assertEquals(segment.byteSize(), 0);
 581             assertEquals(segment.isMapped(), true);
 582             assertFalse(segment.isReadOnly());
 583             segment.force();
 584             segment.load();
 585             segment.isLoaded();
 586             segment.unload();
 587             ByteBuffer byteBuffer = segment.asByteBuffer();
 588             assertEquals(byteBuffer.capacity(), 0);
 589             assertFalse(byteBuffer.isReadOnly());
 590         }
 591         //RO
 592         try (Arena arena = Arena.ofConfined();
 593              FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
 594             MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, 0L, arena);
 595             assertEquals(segment.byteSize(), 0);
 596             assertEquals(segment.isMapped(), true);
 597             assertTrue(segment.isReadOnly());
 598             segment.force();
 599             segment.load();
 600             segment.isLoaded();
 601             segment.unload();
 602             ByteBuffer byteBuffer = segment.asByteBuffer();
 603             assertEquals(byteBuffer.capacity(), 0);
 604             assertTrue(byteBuffer.isReadOnly());
 605         }
 606     }
 607 
 608     @Test(expectedExceptions = UnsupportedOperationException.class)
 609     public void testMapCustomPath() throws IOException {
 610         Path path = Path.of(URI.create("jrt:/"));
 611         try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 612             fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 0L, Arena.ofAuto());
 613         }
 614     }
 615 
 616     @Test(dataProvider="resizeOps")
 617     public void testCopyHeapToNative(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 618         checkByteArrayAlignment(seq.elementLayout());
 619         int bytes = (int)seq.byteSize();
 620         try (Arena arena = Arena.ofConfined()) {
 621             MemorySegment nativeArray = arena.allocate(bytes, 1);;
 622             MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes]);
 623             initializer.accept(heapArray);
 624             nativeArray.copyFrom(heapArray);
 625             checker.accept(nativeArray);
 626         }
 627     }
 628 
 629     @Test(dataProvider="resizeOps")
 630     public void testCopyNativeToHeap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
 631         checkByteArrayAlignment(seq.elementLayout());
 632         int bytes = (int)seq.byteSize();
 633         try (Arena arena = Arena.ofConfined()) {
 634             MemorySegment nativeArray = arena.allocate(seq);;
 635             MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes]);
 636             initializer.accept(nativeArray);
 637             heapArray.copyFrom(nativeArray);
 638             checker.accept(heapArray);
 639         }
 640     }
 641 
 642     @Test
 643     public void testDefaultAccessModesOfBuffer() {
 644         ByteBuffer rwBuffer = ByteBuffer.wrap(new byte[4]);
 645         {
 646             MemorySegment segment = MemorySegment.ofBuffer(rwBuffer);
 647             assertFalse(segment.isReadOnly());
 648         }
 649 
 650         {
 651             ByteBuffer roBuffer = rwBuffer.asReadOnlyBuffer();
 652             MemorySegment segment = MemorySegment.ofBuffer(roBuffer);
 653             assertTrue(segment.isReadOnly());
 654         }
 655     }
 656 
 657     @Test
 658     public void testOfBufferScopeReachable() throws InterruptedException {
 659         ByteBuffer buffer = ByteBuffer.allocateDirect(1000);
 660         MemorySegment segment = MemorySegment.ofBuffer(buffer);
 661         try {
 662             AtomicBoolean reachable = new AtomicBoolean(true);
 663             Cleaner.create().register(buffer, () -> {
 664                 reachable.set(false);
 665             });
 666             buffer = null;
 667             System.gc();
 668             // let's sleep to let cleaner run
 669             Thread.sleep(100);
 670             segment.get(JAVA_BYTE, 0);
 671             if (!reachable.get()) {
 672                 throw new IllegalStateException();
 673             }
 674         } finally {
 675             Reference.reachabilityFence(segment);
 676         }
 677     }
 678 
 679     @Test(dataProvider="bufferSources")
 680     public void testBufferToSegment(ByteBuffer bb, Predicate<MemorySegment> segmentChecker) {
 681         MemorySegment segment = MemorySegment.ofBuffer(bb);
 682         assertEquals(segment.isReadOnly(), bb.isReadOnly());
 683         assertTrue(segmentChecker.test(segment));
 684         assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
 685         assertEquals(bb.capacity(), segment.byteSize());
 686         //another round trip
 687         segment = MemorySegment.ofBuffer(segment.asByteBuffer());
 688         assertEquals(segment.isReadOnly(), bb.isReadOnly());
 689         assertTrue(segmentChecker.test(segment));
 690         assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
 691         assertEquals(bb.capacity(), segment.byteSize());
 692     }
 693 
 694     @Test(dataProvider="bufferSources")
 695     public void bufferProperties(ByteBuffer bb, Predicate<MemorySegment> _unused) {
 696         MemorySegment segment = MemorySegment.ofBuffer(bb);
 697         ByteBuffer buffer = segment.asByteBuffer();
 698         assertEquals(buffer.position(), 0);
 699         assertEquals(buffer.capacity(), segment.byteSize());
 700         assertEquals(buffer.limit(), segment.byteSize());
 701     }
 702 
 703     @Test
 704     public void testRoundTripAccess() {
 705         try (Arena arena = Arena.ofConfined()) {
 706             MemorySegment ms = arena.allocate(4, 1);;
 707             MemorySegment msNoAccess = ms.asReadOnly();
 708             MemorySegment msRoundTrip = MemorySegment.ofBuffer(msNoAccess.asByteBuffer());
 709             assertEquals(msRoundTrip.scope(), ms.scope());
 710             assertEquals(msNoAccess.isReadOnly(), msRoundTrip.isReadOnly());
 711         }
 712     }
 713 
 714     @Test(dataProvider = "bufferFactories")
 715     public void testDerivedBufferScopes(Supplier<Buffer> bufferFactory) {
 716         MemorySegment segment = MemorySegment.ofBuffer(bufferFactory.get());
 717         assertEquals(segment.scope(), segment.scope());
 718         // one level
 719         assertEquals(segment.asSlice(0).scope(), segment.scope());
 720         assertEquals(segment.asReadOnly().scope(), segment.scope());
 721         // two levels
 722         assertEquals(segment.asSlice(0).asReadOnly().scope(), segment.scope());
 723         assertEquals(segment.asReadOnly().asSlice(0).scope(), segment.scope());
 724         // check fresh every time
 725         MemorySegment another = MemorySegment.ofBuffer(bufferFactory.get());
 726         assertNotEquals(segment.scope(), another.scope());
 727     }
 728 
 729     @Test(expectedExceptions = IllegalStateException.class)
 730     public void testDeadAccessOnClosedBufferSegment() {
 731         Arena arena = Arena.ofConfined();
 732         MemorySegment s1 = arena.allocate(JAVA_INT);
 733         MemorySegment s2 = MemorySegment.ofBuffer(s1.asByteBuffer());
 734 
 735         // memory freed
 736         arena.close();
 737 
 738         s2.set(JAVA_INT, 0, 10); // Dead access!
 739     }
 740 
 741     @Test(dataProvider = "closeableArenas")
 742     public void closeableArenas(Supplier<Arena> arenaSupplier) throws IOException {
 743         File tmp = File.createTempFile("tmp", "txt");
 744         tmp.deleteOnExit();
 745         try (FileChannel channel = FileChannel.open(tmp.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE) ;
 746             Arena arena = arenaSupplier.get()) {
 747             MemorySegment segment = arena.allocate(10, 1);;
 748             for (int i = 0; i < 10; i++) {
 749                 segment.set(JAVA_BYTE, i, (byte) i);
 750             }
 751             ByteBuffer bb = segment.asByteBuffer();
 752             assertEquals(channel.write(bb), 10);
 753             segment.fill((byte)0x00);
 754             assertEquals(bb.clear(), ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
 755             assertEquals(channel.position(0).read(bb.clear()), 10);
 756             assertEquals(bb.flip(), ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
 757         }
 758     }
 759 
 760     static final Class<IllegalStateException> ISE = IllegalStateException.class;
 761 
 762     @Test(dataProvider = "closeableArenas")
 763     public void testIOOnClosedSegmentBuffer(Supplier<Arena> arenaSupplier) throws IOException {
 764         File tmp = File.createTempFile("tmp", "txt");
 765         tmp.deleteOnExit();
 766         Arena arena = arenaSupplier.get();
 767         try (FileChannel channel = FileChannel.open(tmp.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 768             MemorySegment segment = arena.allocate(10, 1);
 769             for (int i = 0; i < 10; i++) {
 770                 segment.set(JAVA_BYTE, i, (byte) i);
 771             }
 772             ByteBuffer bb = segment.asByteBuffer();
 773             arena.close();
 774             assertThrows(ISE, () -> channel.read(bb));
 775             assertThrows(ISE, () -> channel.read(new ByteBuffer[] {bb}));
 776             assertThrows(ISE, () -> channel.read(new ByteBuffer[] {bb}, 0, 1));
 777             assertThrows(ISE, () -> channel.write(bb));
 778             assertThrows(ISE, () -> channel.write(new ByteBuffer[] {bb}));
 779             assertThrows(ISE, () -> channel.write(new ByteBuffer[] {bb}, 0 ,1));
 780         }
 781     }
 782 
 783     @Test
 784     public void buffersAndArraysFromSlices() {
 785         try (Arena arena = Arena.ofShared()) {
 786             MemorySegment segment = arena.allocate(16, 1);;
 787             int newSize = 8;
 788             var slice = segment.asSlice(4, newSize);
 789 
 790             var bytes = slice.toArray(JAVA_BYTE);
 791             assertEquals(newSize, bytes.length);
 792 
 793             var buffer = slice.asByteBuffer();
 794             // Fails for heap segments, but passes for native segments:
 795             assertEquals(0, buffer.position());
 796             assertEquals(newSize, buffer.limit());
 797             assertEquals(newSize, buffer.capacity());
 798         }
 799     }
 800 
 801     @Test
 802     public void viewsFromSharedSegment() {
 803         try (Arena arena = Arena.ofShared()) {
 804             MemorySegment segment = arena.allocate(16, 1);;
 805             var byteBuffer = segment.asByteBuffer();
 806             byteBuffer.asReadOnlyBuffer();
 807             byteBuffer.slice(0, 8);
 808         }
 809     }
 810 
 811     @DataProvider(name = "segments")
 812     public static Object[][] segments() throws Throwable {
 813         return new Object[][] {
 814                 { (Supplier<MemorySegment>) () -> Arena.ofAuto().allocate(16, 1)},
 815                 { (Supplier<MemorySegment>) () -> Arena.ofConfined().allocate(16, 1)},
 816                 { (Supplier<MemorySegment>) () -> MemorySegment.ofArray(new byte[16]) }
 817         };
 818     }
 819 
 820     @DataProvider(name = "closeableArenas")
 821     public static Object[][] closeableArenas() {
 822         return new Object[][] {
 823                 { (Supplier<Arena>) Arena::ofConfined},
 824                 { (Supplier<Arena>) Arena::ofShared},
 825         };
 826     }
 827 
 828     @DataProvider(name = "bufferOps")
 829     public static Object[][] bufferOps() throws Throwable {
 830         List<Object[]> args = new ArrayList<>();
 831         bufferOpsArgs(args, bb -> bb, ByteBuffer.class);
 832         bufferOpsArgs(args, ByteBuffer::asCharBuffer, CharBuffer.class);
 833         bufferOpsArgs(args, ByteBuffer::asShortBuffer, ShortBuffer.class);
 834         bufferOpsArgs(args, ByteBuffer::asIntBuffer, IntBuffer.class);
 835         bufferOpsArgs(args, ByteBuffer::asFloatBuffer, FloatBuffer.class);
 836         bufferOpsArgs(args, ByteBuffer::asLongBuffer, LongBuffer.class);
 837         bufferOpsArgs(args, ByteBuffer::asDoubleBuffer, DoubleBuffer.class);
 838         return args.toArray(Object[][]::new);
 839     }
 840 
 841     static void bufferOpsArgs(List<Object[]> argsList, Function<ByteBuffer, Buffer> factory, Class<?> bufferClass) {
 842         for (Method m : bufferClass.getMethods()) {
 843             //skip statics and method declared in j.l.Object
 844             if (m.getDeclaringClass().equals(Object.class)
 845                 || ((m.getModifiers() & Modifier.STATIC) != 0)
 846                 || (!m.getName().contains("get") && !m.getName().contains("put"))
 847                 || m.getParameterCount() > 2) continue;
 848             Object[] args = Stream.of(m.getParameterTypes())
 849                     .map(TestByteBuffer::defaultValue)
 850                     .toArray();
 851             argsList.add(new Object[] { factory, m, args });
 852         }
 853     }
 854 
 855     @DataProvider(name = "bufferHandleOps")
 856     public static Object[][] bufferHandleOps() throws Throwable {
 857         return new Object[][]{
 858                 { MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) },
 859                 { MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder()) },
 860                 { MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.nativeOrder()) },
 861                 { MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder()) },
 862                 { MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.nativeOrder()) },
 863                 { MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.nativeOrder()) }
 864         };
 865     }
 866 
 867     static Map<MethodHandle, Object[]> varHandleMembers(ByteBuffer bb, VarHandle handle) {
 868         Map<MethodHandle, Object[]> members = new HashMap<>();
 869         for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
 870             Class<?>[] params = handle.accessModeType(mode).parameterArray();
 871             Object[] args = Stream.concat(Stream.of(bb), Stream.of(params).skip(1)
 872                     .map(TestByteBuffer::defaultValue))
 873                     .toArray();
 874             try {
 875                 members.put(MethodHandles.varHandleInvoker(mode, handle.accessModeType(mode)), args);
 876             } catch (Throwable ex) {
 877                 throw new AssertionError(ex);
 878             }
 879         }
 880         return members;
 881     }
 882 
 883     @DataProvider(name = "resizeOps")
 884     public Object[][] resizeOps() {
 885         Consumer<MemorySegment> byteInitializer =
 886                 (base) -> initBytes(base, bytes, (addr, pos) -> addr.set(JAVA_BYTE, pos, (byte)(long)pos));
 887         Consumer<MemorySegment> charInitializer =
 888                 (base) -> initBytes(base, chars, (addr, pos) -> addr.setAtIndex(BB_CHAR, pos, (char)(long)pos));
 889         Consumer<MemorySegment> shortInitializer =
 890                 (base) -> initBytes(base, shorts, (addr, pos) -> addr.setAtIndex(BB_SHORT, pos, (short)(long)pos));
 891         Consumer<MemorySegment> intInitializer =
 892                 (base) -> initBytes(base, ints, (addr, pos) -> addr.setAtIndex(BB_INT, pos, (int)(long)pos));
 893         Consumer<MemorySegment> floatInitializer =
 894                 (base) -> initBytes(base, floats, (addr, pos) -> addr.setAtIndex(BB_FLOAT, pos, (float)(long)pos));
 895         Consumer<MemorySegment> longInitializer =
 896                 (base) -> initBytes(base, longs, (addr, pos) -> addr.setAtIndex(BB_LONG, pos, (long)pos));
 897         Consumer<MemorySegment> doubleInitializer =
 898                 (base) -> initBytes(base, doubles, (addr, pos) -> addr.setAtIndex(BB_DOUBLE, pos, (double)(long)pos));
 899 
 900         Consumer<MemorySegment> byteChecker =
 901                 (base) -> checkBytes(base, bytes, Function.identity(), (addr, pos) -> addr.get(JAVA_BYTE, pos), ByteBuffer::get);
 902         Consumer<MemorySegment> charChecker =
 903                 (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, (addr, pos) -> addr.getAtIndex(BB_CHAR, pos), CharBuffer::get);
 904         Consumer<MemorySegment> shortChecker =
 905                 (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, (addr, pos) -> addr.getAtIndex(BB_SHORT, pos), ShortBuffer::get);
 906         Consumer<MemorySegment> intChecker =
 907                 (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, (addr, pos) -> addr.getAtIndex(BB_INT, pos), IntBuffer::get);
 908         Consumer<MemorySegment> floatChecker =
 909                 (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, (addr, pos) -> addr.getAtIndex(BB_FLOAT, pos), FloatBuffer::get);
 910         Consumer<MemorySegment> longChecker =
 911                 (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, (addr, pos) -> addr.getAtIndex(BB_LONG, pos), LongBuffer::get);
 912         Consumer<MemorySegment> doubleChecker =
 913                 (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, (addr, pos) -> addr.getAtIndex(BB_DOUBLE, pos), DoubleBuffer::get);
 914 
 915         return new Object[][]{
 916                 {byteChecker, byteInitializer, bytes},
 917                 {charChecker, charInitializer, chars},
 918                 {shortChecker, shortInitializer, shorts},
 919                 {intChecker, intInitializer, ints},
 920                 {floatChecker, floatInitializer, floats},
 921                 {longChecker, longInitializer, longs},
 922                 {doubleChecker, doubleInitializer, doubles}
 923         };
 924     }
 925 
 926     static Object defaultValue(Class<?> c) {
 927         if (c.isPrimitive()) {
 928             if (c == char.class) {
 929                 return (char)0;
 930             } else if (c == boolean.class) {
 931                 return false;
 932             } else if (c == byte.class) {
 933                 return (byte)0;
 934             } else if (c == short.class) {
 935                 return (short)0;
 936             } else if (c == int.class) {
 937                 return 0;
 938             } else if (c == long.class) {
 939                 return 0L;
 940             } else if (c == float.class) {
 941                 return 0f;
 942             } else if (c == double.class) {
 943                 return 0d;
 944             } else {
 945                 throw new IllegalStateException();
 946             }
 947         } else if (c.isArray()) {
 948             if (c == char[].class) {
 949                 return new char[1];
 950             } else if (c == boolean[].class) {
 951                 return new boolean[1];
 952             } else if (c == byte[].class) {
 953                 return new byte[1];
 954             } else if (c == short[].class) {
 955                 return new short[1];
 956             } else if (c == int[].class) {
 957                 return new int[1];
 958             } else if (c == long[].class) {
 959                 return new long[1];
 960             } else if (c == float[].class) {
 961                 return new float[1];
 962             } else if (c == double[].class) {
 963                 return new double[1];
 964             } else {
 965                 throw new IllegalStateException();
 966             }
 967         } else if (c == String.class) {
 968             return "asdf";
 969         } else if (c == ByteBuffer.class) {
 970             return ByteBuffer.wrap(new byte[1]);
 971         } else if (c == CharBuffer.class) {
 972             return CharBuffer.wrap(new char[1]);
 973         } else if (c == ShortBuffer.class) {
 974             return ShortBuffer.wrap(new short[1]);
 975         } else if (c == IntBuffer.class) {
 976             return IntBuffer.wrap(new int[1]);
 977         } else if (c == FloatBuffer.class) {
 978             return FloatBuffer.wrap(new float[1]);
 979         } else if (c == LongBuffer.class) {
 980             return LongBuffer.wrap(new long[1]);
 981         } else if (c == DoubleBuffer.class) {
 982             return DoubleBuffer.wrap(new double[1]);
 983         } else {
 984             return null;
 985         }
 986     }
 987 
 988     @DataProvider(name = "bufferSources")
 989     public static Object[][] bufferSources() {
 990         Predicate<MemorySegment> heapTest = segment -> segment instanceof HeapMemorySegmentImpl;
 991         Predicate<MemorySegment> nativeTest = segment -> segment instanceof NativeMemorySegmentImpl;
 992         Predicate<MemorySegment> mappedTest = segment -> segment instanceof MappedMemorySegmentImpl;
 993         try (FileChannel channel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 994             return new Object[][]{
 995                     { ByteBuffer.wrap(new byte[256]), heapTest },
 996                     { ByteBuffer.allocate(256), heapTest },
 997                     { ByteBuffer.allocateDirect(256), nativeTest },
 998                     { channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256), mappedTest },
 999 
1000                     { ByteBuffer.wrap(new byte[256]).asReadOnlyBuffer(), heapTest },
1001                     { ByteBuffer.allocate(256).asReadOnlyBuffer(), heapTest },
1002                     { ByteBuffer.allocateDirect(256).asReadOnlyBuffer(), nativeTest },
1003                     { channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256).asReadOnlyBuffer(),
1004                             nativeTest /* this seems to be an existing bug in the BB implementation */ }
1005             };
1006         } catch (IOException ex) {
1007             throw new ExceptionInInitializerError(ex);
1008         }
1009     }
1010 
1011     enum MappedSegmentOp {
1012         LOAD(MemorySegment::load),
1013         UNLOAD(MemorySegment::unload),
1014         IS_LOADED(MemorySegment::isLoaded),
1015         FORCE(MemorySegment::force),
1016         BUFFER_LOAD(m -> ((MappedByteBuffer)m.asByteBuffer()).load()),
1017         BUFFER_IS_LOADED(m -> ((MappedByteBuffer)m.asByteBuffer()).isLoaded()),
1018         BUFFER_FORCE(m -> ((MappedByteBuffer)m.asByteBuffer()).force());
1019 
1020 
1021         private final Consumer<MemorySegment> segmentOp;
1022 
1023         MappedSegmentOp(Consumer<MemorySegment> segmentOp) {
1024             this.segmentOp = segmentOp;
1025         }
1026 
1027         void apply(MemorySegment segment) {
1028             segmentOp.accept(segment);
1029         }
1030     }
1031 
1032     @DataProvider(name = "mappedOps")
1033     public static Object[][] mappedOps() {
1034         return Stream.of(MappedSegmentOp.values())
1035                 .map(op -> new Object[] { op })
1036                 .toArray(Object[][]::new);
1037     }
1038 
1039     @DataProvider(name = "bufferFactories")
1040     public static Object[][] bufferFactories() {
1041         List<Supplier<Buffer>> l = List.of(
1042                 () -> ByteBuffer.allocate(10),
1043                 () -> CharBuffer.allocate(10),
1044                 () -> ShortBuffer.allocate(10),
1045                 () -> IntBuffer.allocate(10),
1046                 () -> FloatBuffer.allocate(10),
1047                 () -> LongBuffer.allocate(10),
1048                 () -> DoubleBuffer.allocate(10),
1049                 () -> ByteBuffer.allocateDirect(10),
1050                 () -> ByteBuffer.allocateDirect(10).asCharBuffer(),
1051                 () -> ByteBuffer.allocateDirect(10).asShortBuffer(),
1052                 () -> ByteBuffer.allocateDirect(10).asIntBuffer(),
1053                 () -> ByteBuffer.allocateDirect(10).asFloatBuffer(),
1054                 () -> ByteBuffer.allocateDirect(10).asLongBuffer(),
1055                 () -> ByteBuffer.allocateDirect(10).asDoubleBuffer()
1056         );
1057         return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new);
1058 
1059     }
1060     @DataProvider(name = "fromArrays")
1061     public static Object[][] fromArrays() {
1062         int len = 16;
1063         return Stream.of(
1064                         MemorySegment.ofArray(new byte[len]),
1065                         MemorySegment.ofArray(new short[len]),
1066                         MemorySegment.ofArray(new char[len]),
1067                         MemorySegment.ofArray(new int[len]),
1068                         MemorySegment.ofArray(new long[len]),
1069                         MemorySegment.ofArray(new float[len]),
1070                         MemorySegment.ofArray(new double[len])
1071                 )
1072                 .map(s -> new Object[] { s })
1073                 .toArray(Object[][]::new);
1074     }
1075 }