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 }