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