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