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