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