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