On Thu, 20 Jul 2023 14:49:48 GMT, Glavo <d...@openjdk.org> wrote: >> Also, note that ByteBuffer exposes its backing array (at least if the buffer >> is not read only) via ByteBuffer::array. This does no copy. So in all the >> various stream implementations, I believe we can really just use a >> ByteBuffer instead of an array - and use ByteBuffer::array when we really >> need an array. >> >> This makes it very easy to migrate some of the classes that use ByteArray. >> Here's the patch for DataInputStream: >> >> >> diff --git a/src/java.base/share/classes/java/io/DataInputStream.java >> b/src/java.base/share/classes/java/io/DataInputStream.java >> index 7192b30d5f2..b5b013cdd50 100644 >> --- a/src/java.base/share/classes/java/io/DataInputStream.java >> +++ b/src/java.base/share/classes/java/io/DataInputStream.java >> @@ -27,6 +27,8 @@ package java.io; >> >> import jdk.internal.util.ByteArray; >> >> +import java.nio.ByteBuffer; >> +import java.nio.ByteOrder; >> import java.util.Objects; >> >> /** >> @@ -59,7 +61,7 @@ public class DataInputStream extends FilterInputStream >> implements DataInput { >> super(in); >> } >> >> - private final byte[] readBuffer = new byte[8]; >> + private final ByteBuffer readBuffer = ByteBuffer.allocate(8); // >> BIG_ENDIAN >> >> /** >> * working arrays initialized on demand by readUTF >> @@ -316,8 +318,8 @@ public class DataInputStream extends FilterInputStream >> implements DataInput { >> * @see java.io.FilterInputStream#in >> */ >> public final short readShort() throws IOException { >> - readFully(readBuffer, 0, 2); >> - return ByteArray.getShort(readBuffer, 0); >> + readFully(readBuffer.array(), 0, 2); >> + return readBuffer.getShort(0); >> } >> >> /** >> @@ -338,8 +340,8 @@ public class DataInputStream extends FilterInputStream >> implements DataInput { >> * @see java.io.FilterInputStream#in >> */ >> public final int readUnsignedShort() throws IOException { >> - readFully(readBuffer, 0, 2); >> - return ByteArray.getUnsignedShort(readBuffer, 0); >> + readFully(readBuffer.array(), 0, 2); >> + return Short.toUnsignedInt(readBuffer.getShort(0)); >> } >> >> /** >> @@ -360,8 +362,8 @@ public class DataInputStream extends FilterInputStream >> implements DataInput { >> * @see java.io.FilterInputStream#in >> */ >> public final char readChar() throws IOException { >> - readFully(readBuffer, 0, 2); >> - return ByteArray.getChar(readBuffer, 0); >> + readFully(readBuffer.arra... > > @mcimadamore I compared the performance of `ByteBuffer` and `VarHandle` using > a JMH benchmark: > > > public class ByteArray { > > private byte[] array; > private ByteBuffer byteBuffer; > > private static final VarHandle INT = > MethodHandles.byteArrayViewVarHandle(int[].class, LITTLE_ENDIAN); > private static final VarHandle LONG = > MethodHandles.byteArrayViewVarHandle(long[].class, LITTLE_ENDIAN); > > @Setup > public void setup() { > array = new byte[8]; > byteBuffer = ByteBuffer.wrap(array).order(LITTLE_ENDIAN); > > new Random(0).nextBytes(array); > } > > @Benchmark > public byte readByte() { > return array[0]; > } > > @Benchmark > public byte readByteFromBuffer() { > return byteBuffer.get(0); > } > > @Benchmark > public int readInt() { > return (int) INT.get(array, 0); > } > > @Benchmark > public int readIntFromBuffer() { > return byteBuffer.getInt(0); > } > > > @Benchmark > public long readLong() { > return (long) LONG.get(array, 0); > } > > @Benchmark > public long readLongFromBuffer() { > return byteBuffer.getLong(0); > } > } > > > Result: > > Benchmark Mode Cnt Score Error Units > ByteArray.readByte thrpt 5 1270230.180 ± 29172.551 ops/ms > ByteArray.readByteFromBuffer thrpt 5 623862.080 ± 12167.410 ops/ms > ByteArray.readInt thrpt 5 1252719.463 ± 77598.672 ops/ms > ByteArray.readIntFromBuffer thrpt 5 571070.474 ± 1500.426 ops/ms > ByteArray.readLong thrpt 5 1262720.686 ± 728.100 ops/ms > ByteArray.readLongFromBuffer thrpt 5 571594.800 ± 3376.735 ops/ms > > > In this result, ByteBuffer is much slower than VarHandle. Am I doing > something wrong? What conditions are needed to make the performance of > ByteBuffer close to that of Unsafe?
I tried a few more. It looks like the JIT is able to optimize the ByteBuffer away pretty well by keeping it only as a local variable without escaping. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/14636#discussion_r1269582991