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.MemoryLayouts;
35 import jdk.incubator.foreign.MemoryLayout;
36 import jdk.incubator.foreign.MemoryAddress;
37 import jdk.incubator.foreign.MemorySegment;
38 import jdk.incubator.foreign.MemoryLayout.PathElement;
39 import jdk.incubator.foreign.SequenceLayout;
40 
41 import java.io.File;
42 import java.lang.invoke.MethodHandle;
43 import java.lang.invoke.MethodHandles;
44 import java.lang.invoke.VarHandle;
45 import java.lang.ref.WeakReference;
46 import java.lang.reflect.InvocationTargetException;
47 import java.lang.reflect.Method;
48 import java.lang.reflect.Modifier;
49 import java.nio.Buffer;
50 import java.nio.ByteBuffer;
51 import java.nio.ByteOrder;
52 import java.nio.CharBuffer;
53 import java.nio.DoubleBuffer;
54 import java.nio.FloatBuffer;
55 import java.nio.IntBuffer;
56 import java.nio.InvalidMarkException;
57 import java.nio.LongBuffer;
58 import java.nio.MappedByteBuffer;
59 import java.nio.ShortBuffer;
60 import java.nio.channels.FileChannel;
61 import java.nio.file.StandardOpenOption;
62 import java.util.HashMap;
63 import java.util.Map;
64 import java.util.Optional;
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.Supplier;
70 import java.util.stream.Stream;
71 
72 import jdk.internal.foreign.MemoryAddressImpl;
73 import org.testng.SkipException;
74 import org.testng.annotations.*;
75 import sun.nio.ch.DirectBuffer;
76 
77 import static org.testng.Assert.*;
78 
79 public class TestByteBuffer {
80 
81     static SequenceLayout tuples = MemoryLayout.ofSequence(500,
82             MemoryLayout.ofStruct(
83                     MemoryLayouts.BITS_32_BE.withName("index"),
84                     MemoryLayouts.BITS_32_BE.withName("value")
85             ));
86 
87     static SequenceLayout bytes = MemoryLayout.ofSequence(100,
88             MemoryLayouts.BITS_8_BE
89     );
90 
91     static SequenceLayout chars = MemoryLayout.ofSequence(100,
92             MemoryLayouts.BITS_16_BE
93     );
94 
95     static SequenceLayout shorts = MemoryLayout.ofSequence(100,
96             MemoryLayouts.BITS_16_BE
97     );
98 
99     static SequenceLayout ints = MemoryLayout.ofSequence(100,
100             MemoryLayouts.BITS_32_BE
101     );
102 
103     static SequenceLayout floats = MemoryLayout.ofSequence(100,
104             MemoryLayouts.BITS_32_BE
105     );
106 
107     static SequenceLayout longs = MemoryLayout.ofSequence(100,
108             MemoryLayouts.BITS_64_BE
109     );
110 
111     static SequenceLayout doubles = MemoryLayout.ofSequence(100,
112             MemoryLayouts.BITS_64_BE
113     );
114 
115     static VarHandle indexHandle = tuples.varHandle(int.class, PathElement.sequenceElement(), PathElement.groupElement("index"));
116     static VarHandle valueHandle = tuples.varHandle(float.class, PathElement.sequenceElement(), PathElement.groupElement("value"));
117 
118     static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement());
119     static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement());
120     static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement());
121     static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement());
122     static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement());
123     static VarHandle longHandle = longs.varHandle(long.class, PathElement.sequenceElement());
124     static VarHandle doubleHandle = doubles.varHandle(double.class, PathElement.sequenceElement());
125 
126 
initTuples(MemoryAddress base)127     static void initTuples(MemoryAddress base) {
128         for (long i = 0; i < tuples.elementCount().getAsLong() ; i++) {
129             indexHandle.set(base, i, (int)i);
130             valueHandle.set(base, i, (float)(i / 500f));
131         }
132     }
133 
checkTuples(MemoryAddress base, ByteBuffer bb)134     static void checkTuples(MemoryAddress base, ByteBuffer bb) {
135         for (long i = 0; i < tuples.elementCount().getAsLong() ; i++) {
136             assertEquals(bb.getInt(), (int)indexHandle.get(base, i));
137             assertEquals(bb.getFloat(), (float)valueHandle.get(base, i));
138         }
139     }
140 
initBytes(MemoryAddress base, SequenceLayout seq, BiConsumer<MemoryAddress, Long> handleSetter)141     static void initBytes(MemoryAddress base, SequenceLayout seq, BiConsumer<MemoryAddress, Long> handleSetter) {
142         for (long i = 0; i < seq.elementCount().getAsLong() ; i++) {
143             handleSetter.accept(base, i);
144         }
145     }
146 
checkBytes(MemoryAddress base, SequenceLayout layout, Function<ByteBuffer, Z> bufFactory, BiFunction<MemoryAddress, Long, Object> handleExtractor, Function<Z, Object> bufferExtractor)147     static <Z extends Buffer> void checkBytes(MemoryAddress base, SequenceLayout layout,
148                                               Function<ByteBuffer, Z> bufFactory,
149                                               BiFunction<MemoryAddress, Long, Object> handleExtractor,
150                                               Function<Z, Object> bufferExtractor) {
151         long nelems = layout.elementCount().getAsLong();
152         long elemSize = layout.elementLayout().byteSize();
153         for (long i = 0 ; i < nelems ; i++) {
154             long limit = nelems - i;
155             MemorySegment resizedSegment = base.segment().asSlice(i * elemSize, limit * elemSize);
156             ByteBuffer bb = resizedSegment.asByteBuffer();
157             Z z = bufFactory.apply(bb);
158             for (long j = i ; j < limit ; j++) {
159                 Object handleValue = handleExtractor.apply(resizedSegment.baseAddress(), j - i);
160                 Object bufferValue = bufferExtractor.apply(z);
161                 if (handleValue instanceof Number) {
162                     assertEquals(((Number)handleValue).longValue(), j);
163                     assertEquals(((Number)bufferValue).longValue(), j);
164                 } else {
165                     assertEquals((long)(char)handleValue, j);
166                     assertEquals((long)(char)bufferValue, j);
167                 }
168             }
169         }
170     }
171 
172     @Test
testOffheap()173     public void testOffheap() {
174         try (MemorySegment segment = MemorySegment.allocateNative(tuples)) {
175             MemoryAddress base = segment.baseAddress();
176             initTuples(base);
177 
178             ByteBuffer bb = segment.asByteBuffer();
179             checkTuples(base, bb);
180         }
181     }
182 
183     @Test
testHeap()184     public void testHeap() {
185         byte[] arr = new byte[(int) tuples.byteSize()];
186         MemorySegment region = MemorySegment.ofArray(arr);
187         MemoryAddress base = region.baseAddress();
188         initTuples(base);
189 
190         ByteBuffer bb = region.asByteBuffer();
191         checkTuples(base, bb);
192     }
193 
194     @Test
testChannel()195     public void testChannel() throws Throwable {
196         File f = new File("test.out");
197         assertTrue(f.createNewFile());
198         f.deleteOnExit();
199 
200         //write to channel
201         try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
202             withMappedBuffer(channel, FileChannel.MapMode.READ_WRITE, 0, tuples.byteSize(), mbb -> {
203                 MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
204                 MemoryAddress base = segment.baseAddress();
205                 initTuples(base);
206                 mbb.force();
207             });
208         }
209 
210         //read from channel
211         try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
212             withMappedBuffer(channel, FileChannel.MapMode.READ_ONLY, 0, tuples.byteSize(), mbb -> {
213                 MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
214                 MemoryAddress base = segment.baseAddress();
215                 checkTuples(base, mbb);
216             });
217         }
218     }
219 
220     @Test
testMappedSegment()221     public void testMappedSegment() throws Throwable {
222         File f = new File("test2.out");
223         f.createNewFile();
224         f.deleteOnExit();
225 
226         //write to channel
227         try (MemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_WRITE)) {
228             MemoryAddress base = segment.baseAddress();
229             initTuples(base);
230         }
231 
232         //read from channel
233         try (MemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_ONLY)) {
234             MemoryAddress base = segment.baseAddress();
235             checkTuples(base, segment.asByteBuffer());
236         }
237     }
238 
withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action)239     static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action) throws Throwable {
240         MappedByteBuffer mbb = channel.map(mode, pos, size);
241         var ref = new WeakReference<>(mbb);
242         action.accept(mbb);
243         mbb = null;
244         //wait for it to be GCed
245         System.gc();
246         while (ref.get() != null) {
247             Thread.sleep(20);
248         }
249     }
250 
checkByteArrayAlignment(MemoryLayout layout)251     static void checkByteArrayAlignment(MemoryLayout layout) {
252         if (layout.bitSize() > 32
253                 && System.getProperty("sun.arch.data.model").equals("32")) {
254             throw new SkipException("avoid unaligned access on 32-bit system");
255         }
256     }
257 
258     @Test(dataProvider = "bufferOps")
testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members)259     public void testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
260         Buffer bb;
261         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
262             MemoryAddress base = segment.baseAddress();
263             bb = bufferFactory.apply(segment.asByteBuffer());
264         }
265         //outside of scope!!
266         for (Map.Entry<Method, Object[]> e : members.entrySet()) {
267             if (!e.getKey().getName().contains("get") &&
268                             !e.getKey().getName().contains("put")) {
269                 //skip
270                 return;
271             }
272             try {
273                 e.getKey().invoke(bb, e.getValue());
274                 assertTrue(false);
275             } catch (InvocationTargetException ex) {
276                 Throwable cause = ex.getCause();
277                 if (cause instanceof IllegalStateException) {
278                     //all get/set buffer operation should fail because of the scope check
279                     assertTrue(ex.getCause().getMessage().contains("not alive"));
280                 } else {
281                     //all other exceptions were unexpected - fail
282                     assertTrue(false);
283                 }
284             } catch (Throwable ex) {
285                 //unexpected exception - fail
286                 assertTrue(false);
287             }
288         }
289     }
290 
291     @Test(dataProvider = "bufferHandleOps")
testScopedBufferAndVarHandle(VarHandle bufferHandle)292     public void testScopedBufferAndVarHandle(VarHandle bufferHandle) {
293         ByteBuffer bb;
294         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
295             bb = segment.asByteBuffer();
296             for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
297                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
298                         .asSpreader(Object[].class, e.getValue().length);
299                 try {
300                     handle.invoke(e.getValue());
301                 } catch (UnsupportedOperationException ex) {
302                     //skip
303                 } catch (Throwable ex) {
304                     //should not fail - segment is alive!
305                     fail();
306                 }
307             }
308         }
309         for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
310             try {
311                 MethodHandle handle = e.getKey().bindTo(bufferHandle)
312                         .asSpreader(Object[].class, e.getValue().length);
313                 handle.invoke(e.getValue());
314                 fail();
315             } catch (IllegalStateException ex) {
316                 assertTrue(ex.getMessage().contains("not alive"));
317             } catch (UnsupportedOperationException ex) {
318                 //skip
319             } catch (Throwable ex) {
320                 fail();
321             }
322         }
323     }
324 
325     @Test(dataProvider = "bufferOps")
testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members)326     public void testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
327         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
328             MemoryAddress base = segment.baseAddress();
329             Buffer bb = bufferFactory.apply(segment.asByteBuffer());
330             assertTrue(bb.isDirect());
331             DirectBuffer directBuffer = ((DirectBuffer)bb);
332             assertEquals(directBuffer.address(), ((MemoryAddressImpl)base).unsafeGetOffset());
333             assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer));
334             assertTrue(directBuffer.cleaner() == null);
335         }
336     }
337 
338     @Test(dataProvider="resizeOps")
testResizeOffheap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)339     public void testResizeOffheap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
340         try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
341             MemoryAddress base = segment.baseAddress();
342             initializer.accept(base);
343             checker.accept(base);
344         }
345     }
346 
347     @Test(dataProvider="resizeOps")
testResizeHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)348     public void testResizeHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
349         checkByteArrayAlignment(seq.elementLayout());
350         int capacity = (int)seq.byteSize();
351         MemoryAddress base = MemorySegment.ofArray(new byte[capacity]).baseAddress();
352         initializer.accept(base);
353         checker.accept(base);
354     }
355 
356     @Test(dataProvider="resizeOps")
testResizeBuffer(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)357     public void testResizeBuffer(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
358         checkByteArrayAlignment(seq.elementLayout());
359         int capacity = (int)seq.byteSize();
360         MemoryAddress base = MemorySegment.ofByteBuffer(ByteBuffer.wrap(new byte[capacity])).baseAddress();
361         initializer.accept(base);
362         checker.accept(base);
363     }
364 
365     @Test(dataProvider="resizeOps")
testResizeRoundtripHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)366     public void testResizeRoundtripHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
367         checkByteArrayAlignment(seq.elementLayout());
368         int capacity = (int)seq.byteSize();
369         byte[] arr = new byte[capacity];
370         MemorySegment segment = MemorySegment.ofArray(arr);
371         MemoryAddress first = segment.baseAddress();
372         initializer.accept(first);
373         MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
374         checker.accept(second);
375     }
376 
377     @Test(dataProvider="resizeOps")
testResizeRoundtripNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)378     public void testResizeRoundtripNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
379         try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
380             MemoryAddress first = segment.baseAddress();
381             initializer.accept(first);
382             MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
383             checker.accept(second);
384         }
385     }
386 
387     @Test(expectedExceptions = IllegalStateException.class)
testBufferOnClosedScope()388     public void testBufferOnClosedScope() {
389         MemorySegment leaked;
390         try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
391             leaked = segment;
392         }
393         leaked.asByteBuffer();
394     }
395 
396     @Test(expectedExceptions = { UnsupportedOperationException.class,
397                                  OutOfMemoryError.class })
testTooBigForByteBuffer()398     public void testTooBigForByteBuffer() {
399         if (System.getProperty("sun.arch.data.model").equals("32")) {
400             throw new SkipException("32-bit Unsafe does not support this allocation size");
401         }
402 
403         MemorySegment.allocateNative((long) Integer.MAX_VALUE * 2).asByteBuffer();
404     }
405 
406     @Test(dataProvider="resizeOps")
testCopyHeapToNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)407     public void testCopyHeapToNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
408         checkByteArrayAlignment(seq.elementLayout());
409         int bytes = (int)seq.byteSize();
410         try (MemorySegment nativeArray = MemorySegment.allocateNative(bytes);
411              MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
412             initializer.accept(heapArray.baseAddress());
413             MemoryAddress.copy(heapArray.baseAddress(), nativeArray.baseAddress(), bytes);
414             checker.accept(nativeArray.baseAddress());
415         }
416     }
417 
418     @Test(dataProvider="resizeOps")
testCopyNativeToHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq)419     public void testCopyNativeToHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
420         checkByteArrayAlignment(seq.elementLayout());
421         int bytes = (int)seq.byteSize();
422         try (MemorySegment nativeArray = MemorySegment.allocateNative(seq);
423              MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
424             initializer.accept(nativeArray.baseAddress());
425             MemoryAddress.copy(nativeArray.baseAddress(), heapArray.baseAddress(), bytes);
426             checker.accept(heapArray.baseAddress());
427         }
428     }
429 
430     @DataProvider(name = "bufferOps")
bufferOps()431     public static Object[][] bufferOps() throws Throwable {
432         return new Object[][]{
433                 { (Function<ByteBuffer, Buffer>) bb -> bb, bufferMembers(ByteBuffer.class)},
434                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asCharBuffer, bufferMembers(CharBuffer.class)},
435                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asShortBuffer, bufferMembers(ShortBuffer.class)},
436                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asIntBuffer, bufferMembers(IntBuffer.class)},
437                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asFloatBuffer, bufferMembers(FloatBuffer.class)},
438                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asLongBuffer, bufferMembers(LongBuffer.class)},
439                 { (Function<ByteBuffer, Buffer>) ByteBuffer::asDoubleBuffer, bufferMembers(DoubleBuffer.class)},
440         };
441     }
442 
bufferMembers(Class<?> bufferClass)443     static Map<Method, Object[]> bufferMembers(Class<?> bufferClass) {
444         Map<Method, Object[]> members = new HashMap<>();
445         for (Method m : bufferClass.getMethods()) {
446             //skip statics and method declared in j.l.Object
447             if (m.getDeclaringClass().equals(Object.class) ||
448                     (m.getModifiers() & Modifier.STATIC) != 0) continue;
449             Object[] args = Stream.of(m.getParameterTypes())
450                     .map(TestByteBuffer::defaultValue)
451                     .toArray();
452             members.put(m, args);
453         }
454         return members;
455     }
456 
457     @DataProvider(name = "bufferHandleOps")
bufferHandleOps()458     public static Object[][] bufferHandleOps() throws Throwable {
459         return new Object[][]{
460                 { MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) },
461                 { MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder()) },
462                 { MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.nativeOrder()) },
463                 { MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder()) },
464                 { MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.nativeOrder()) },
465                 { MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.nativeOrder()) }
466         };
467     }
468 
varHandleMembers(ByteBuffer bb, VarHandle handle)469     static Map<MethodHandle, Object[]> varHandleMembers(ByteBuffer bb, VarHandle handle) {
470         Map<MethodHandle, Object[]> members = new HashMap<>();
471         for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
472             Class<?>[] params = handle.accessModeType(mode).parameterArray();
473             Object[] args = Stream.concat(Stream.of(bb), Stream.of(params).skip(1)
474                     .map(TestByteBuffer::defaultValue))
475                     .toArray();
476             try {
477                 members.put(MethodHandles.varHandleInvoker(mode, handle.accessModeType(mode)), args);
478             } catch (Throwable ex) {
479                 throw new AssertionError(ex);
480             }
481         }
482         return members;
483     }
484 
485     @DataProvider(name = "resizeOps")
resizeOps()486     public Object[][] resizeOps() {
487         Consumer<MemoryAddress> byteInitializer =
488                 (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
489         Consumer<MemoryAddress> charInitializer =
490                 (base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
491         Consumer<MemoryAddress> shortInitializer =
492                 (base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
493         Consumer<MemoryAddress> intInitializer =
494                 (base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
495         Consumer<MemoryAddress> floatInitializer =
496                 (base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
497         Consumer<MemoryAddress> longInitializer =
498                 (base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
499         Consumer<MemoryAddress> doubleInitializer =
500                 (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
501 
502         Consumer<MemoryAddress> byteChecker =
503                 (base) -> checkBytes(base, bytes, Function.identity(), byteHandle::get, ByteBuffer::get);
504         Consumer<MemoryAddress> charChecker =
505                 (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, charHandle::get, CharBuffer::get);
506         Consumer<MemoryAddress> shortChecker =
507                 (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, shortHandle::get, ShortBuffer::get);
508         Consumer<MemoryAddress> intChecker =
509                 (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, intHandle::get, IntBuffer::get);
510         Consumer<MemoryAddress> floatChecker =
511                 (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, floatHandle::get, FloatBuffer::get);
512         Consumer<MemoryAddress> longChecker =
513                 (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, longHandle::get, LongBuffer::get);
514         Consumer<MemoryAddress> doubleChecker =
515                 (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, doubleHandle::get, DoubleBuffer::get);
516 
517         return new Object[][]{
518                 {byteChecker, byteInitializer, bytes},
519                 {charChecker, charInitializer, chars},
520                 {shortChecker, shortInitializer, shorts},
521                 {intChecker, intInitializer, ints},
522                 {floatChecker, floatInitializer, floats},
523                 {longChecker, longInitializer, longs},
524                 {doubleChecker, doubleInitializer, doubles}
525         };
526     }
527 
defaultValue(Class<?> c)528     static Object defaultValue(Class<?> c) {
529         if (c.isPrimitive()) {
530             if (c == char.class) {
531                 return (char)0;
532             } else if (c == boolean.class) {
533                 return false;
534             } else if (c == byte.class) {
535                 return (byte)0;
536             } else if (c == short.class) {
537                 return (short)0;
538             } else if (c == int.class) {
539                 return 0;
540             } else if (c == long.class) {
541                 return 0L;
542             } else if (c == float.class) {
543                 return 0f;
544             } else if (c == double.class) {
545                 return 0d;
546             } else {
547                 throw new IllegalStateException();
548             }
549         } else if (c.isArray()) {
550             if (c == char[].class) {
551                 return new char[1];
552             } else if (c == boolean[].class) {
553                 return new boolean[1];
554             } else if (c == byte[].class) {
555                 return new byte[1];
556             } else if (c == short[].class) {
557                 return new short[1];
558             } else if (c == int[].class) {
559                 return new int[1];
560             } else if (c == long[].class) {
561                 return new long[1];
562             } else if (c == float[].class) {
563                 return new float[1];
564             } else if (c == double[].class) {
565                 return new double[1];
566             } else {
567                 throw new IllegalStateException();
568             }
569         } else {
570             return null;
571         }
572     }
573 }
574