8300236: Use VarHandle access in Data(Input | Output)Stream classes
Reviewed-by: rriggs, alanb
This commit is contained in:
parent
a5d8e12872
commit
74e1a8bfa8
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Utility methods for packing/unpacking primitive values in/out of byte arrays
|
||||
* using big-endian byte ordering (i.e. "Network Order").
|
||||
*/
|
||||
final class Bits {
|
||||
private Bits() {}
|
||||
|
||||
private static final VarHandle SHORT = create(short[].class);
|
||||
private static final VarHandle INT = create(int[].class);
|
||||
private static final VarHandle LONG = create(long[].class);
|
||||
|
||||
/*
|
||||
* Methods for unpacking primitive values from byte arrays starting at
|
||||
* given offsets.
|
||||
*/
|
||||
|
||||
static boolean getBoolean(byte[] b, int off) {
|
||||
return b[off] != 0;
|
||||
}
|
||||
|
||||
static char getChar(byte[] b, int off) {
|
||||
return (char) (short) SHORT.get(b, off);
|
||||
}
|
||||
|
||||
static short getShort(byte[] b, int off) {
|
||||
return (short) SHORT.get(b, off);
|
||||
}
|
||||
|
||||
static int getInt(byte[] b, int off) {
|
||||
return (int) INT.get(b, off);
|
||||
}
|
||||
|
||||
static float getFloat(byte[] b, int off) {
|
||||
// Using Float.intBitsToFloat collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
return Float.intBitsToFloat((int) INT.get(b, off));
|
||||
}
|
||||
|
||||
static long getLong(byte[] b, int off) {
|
||||
return (long) LONG.get(b, off);
|
||||
}
|
||||
|
||||
static double getDouble(byte[] b, int off) {
|
||||
// Using Double.longBitsToDouble collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
return Double.longBitsToDouble((long) LONG.get(b, off));
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods for packing primitive values into byte arrays starting at given
|
||||
* offsets.
|
||||
*/
|
||||
|
||||
static void putBoolean(byte[] b, int off, boolean val) {
|
||||
b[off] = (byte) (val ? 1 : 0);
|
||||
}
|
||||
|
||||
static void putChar(byte[] b, int off, char val) {
|
||||
SHORT.set(b, off, (short) val);
|
||||
}
|
||||
|
||||
static void putShort(byte[] b, int off, short val) {
|
||||
SHORT.set(b, off, val);
|
||||
}
|
||||
|
||||
static void putInt(byte[] b, int off, int val) {
|
||||
INT.set(b, off, val);
|
||||
}
|
||||
|
||||
static void putFloat(byte[] b, int off, float val) {
|
||||
// Using Float.floatToIntBits collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
INT.set(b, off, Float.floatToIntBits(val));
|
||||
}
|
||||
|
||||
static void putLong(byte[] b, int off, long val) {
|
||||
LONG.set(b, off, val);
|
||||
}
|
||||
|
||||
static void putDouble(byte[] b, int off, double val) {
|
||||
// Using Double.doubleToLongBits collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
LONG.set(b, off, Double.doubleToLongBits(val));
|
||||
}
|
||||
|
||||
private static VarHandle create(Class<?> viewArrayClass) {
|
||||
return MethodHandles.byteArrayViewVarHandle(viewArrayClass, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package java.io;
|
||||
|
||||
import jdk.internal.util.ByteArray;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -54,6 +56,8 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
super(in);
|
||||
}
|
||||
|
||||
private final byte[] readBuffer = new byte[8];
|
||||
|
||||
/**
|
||||
* working arrays initialized on demand by readUTF
|
||||
*/
|
||||
@ -309,7 +313,8 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public final short readShort() throws IOException {
|
||||
return (short) readUnsignedShort();
|
||||
readFully(readBuffer, 0, 2);
|
||||
return ByteArray.getShort(readBuffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,12 +335,8 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public final int readUnsignedShort() throws IOException {
|
||||
InputStream in = this.in;
|
||||
int ch1 = in.read();
|
||||
int ch2 = in.read();
|
||||
if ((ch1 | ch2) < 0)
|
||||
throw new EOFException();
|
||||
return (ch1 << 8) + (ch2 << 0);
|
||||
readFully(readBuffer, 0, 2);
|
||||
return ByteArray.getUnsignedShort(readBuffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,7 +357,8 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public final char readChar() throws IOException {
|
||||
return (char) readUnsignedShort();
|
||||
readFully(readBuffer, 0, 2);
|
||||
return ByteArray.getChar(readBuffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -377,18 +379,10 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public final int readInt() throws IOException {
|
||||
InputStream in = this.in;
|
||||
int ch1 = in.read();
|
||||
int ch2 = in.read();
|
||||
int ch3 = in.read();
|
||||
int ch4 = in.read();
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0)
|
||||
throw new EOFException();
|
||||
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
|
||||
readFully(readBuffer, 0, 4);
|
||||
return ByteArray.getInt(readBuffer, 0);
|
||||
}
|
||||
|
||||
private final byte[] readBuffer = new byte[8];
|
||||
|
||||
/**
|
||||
* See the general contract of the {@code readLong}
|
||||
* method of {@code DataInput}.
|
||||
@ -408,14 +402,7 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
*/
|
||||
public final long readLong() throws IOException {
|
||||
readFully(readBuffer, 0, 8);
|
||||
return (((long)readBuffer[0] << 56) +
|
||||
((long)(readBuffer[1] & 255) << 48) +
|
||||
((long)(readBuffer[2] & 255) << 40) +
|
||||
((long)(readBuffer[3] & 255) << 32) +
|
||||
((long)(readBuffer[4] & 255) << 24) +
|
||||
((readBuffer[5] & 255) << 16) +
|
||||
((readBuffer[6] & 255) << 8) +
|
||||
((readBuffer[7] & 255) << 0));
|
||||
return ByteArray.getLong(readBuffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -437,7 +424,8 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
* @see java.lang.Float#intBitsToFloat(int)
|
||||
*/
|
||||
public final float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat(readInt());
|
||||
readFully(readBuffer, 0, 4);
|
||||
return ByteArray.getFloat(readBuffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -459,7 +447,8 @@ public class DataInputStream extends FilterInputStream implements DataInput {
|
||||
* @see java.lang.Double#longBitsToDouble(long)
|
||||
*/
|
||||
public final double readDouble() throws IOException {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
readFully(readBuffer, 0, 8);
|
||||
return ByteArray.getDouble(readBuffer, 0);
|
||||
}
|
||||
|
||||
private char[] lineBuffer;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package java.io;
|
||||
|
||||
import jdk.internal.util.ByteArray;
|
||||
|
||||
/**
|
||||
* A data output stream lets an application write primitive Java data
|
||||
* types to an output stream in a portable way. An application can
|
||||
@ -170,8 +172,7 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
* @see java.io.FilterOutputStream#out
|
||||
*/
|
||||
public final void writeShort(int v) throws IOException {
|
||||
writeBuffer[0] = (byte)(v >>> 8);
|
||||
writeBuffer[1] = (byte)(v >>> 0);
|
||||
ByteArray.setUnsignedShort(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 2);
|
||||
incCount(2);
|
||||
}
|
||||
@ -186,8 +187,7 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
* @see java.io.FilterOutputStream#out
|
||||
*/
|
||||
public final void writeChar(int v) throws IOException {
|
||||
writeBuffer[0] = (byte)(v >>> 8);
|
||||
writeBuffer[1] = (byte)(v >>> 0);
|
||||
ByteArray.setUnsignedShort(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 2);
|
||||
incCount(2);
|
||||
}
|
||||
@ -202,10 +202,7 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
* @see java.io.FilterOutputStream#out
|
||||
*/
|
||||
public final void writeInt(int v) throws IOException {
|
||||
writeBuffer[0] = (byte)(v >>> 24);
|
||||
writeBuffer[1] = (byte)(v >>> 16);
|
||||
writeBuffer[2] = (byte)(v >>> 8);
|
||||
writeBuffer[3] = (byte)(v >>> 0);
|
||||
ByteArray.setInt(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 4);
|
||||
incCount(4);
|
||||
}
|
||||
@ -220,14 +217,7 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
* @see java.io.FilterOutputStream#out
|
||||
*/
|
||||
public final void writeLong(long v) throws IOException {
|
||||
writeBuffer[0] = (byte)(v >>> 56);
|
||||
writeBuffer[1] = (byte)(v >>> 48);
|
||||
writeBuffer[2] = (byte)(v >>> 40);
|
||||
writeBuffer[3] = (byte)(v >>> 32);
|
||||
writeBuffer[4] = (byte)(v >>> 24);
|
||||
writeBuffer[5] = (byte)(v >>> 16);
|
||||
writeBuffer[6] = (byte)(v >>> 8);
|
||||
writeBuffer[7] = (byte)(v >>> 0);
|
||||
ByteArray.setLong(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 8);
|
||||
incCount(8);
|
||||
}
|
||||
@ -246,7 +236,9 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
* @see java.lang.Float#floatToIntBits(float)
|
||||
*/
|
||||
public final void writeFloat(float v) throws IOException {
|
||||
writeInt(Float.floatToIntBits(v));
|
||||
ByteArray.setFloat(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 4);
|
||||
incCount(4);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,7 +255,9 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
* @see java.lang.Double#doubleToLongBits(double)
|
||||
*/
|
||||
public final void writeDouble(double v) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(v));
|
||||
ByteArray.setDouble(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 8);
|
||||
incCount(8);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -301,8 +295,7 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
int len = s.length();
|
||||
for (int i = 0 ; i < len ; i++) {
|
||||
int v = s.charAt(i);
|
||||
writeBuffer[0] = (byte)(v >>> 8);
|
||||
writeBuffer[1] = (byte)(v >>> 0);
|
||||
ByteArray.setUnsignedShort(writeBuffer, 0, v);
|
||||
out.write(writeBuffer, 0, 2);
|
||||
}
|
||||
incCount(len * 2);
|
||||
@ -379,9 +372,8 @@ public class DataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
|
||||
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
|
||||
|
||||
ByteArray.setUnsignedShort(bytearr, count, utflen);
|
||||
count += 2;
|
||||
int i = 0;
|
||||
for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII
|
||||
int c = str.charAt(i);
|
||||
|
@ -45,6 +45,7 @@ import java.util.Objects;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.event.DeserializationEvent;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ByteArray;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
@ -2631,7 +2632,7 @@ public class ObjectInputStream
|
||||
|
||||
public boolean get(String name, boolean val) {
|
||||
int off = getFieldOffset(name, Boolean.TYPE);
|
||||
return (off >= 0) ? Bits.getBoolean(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
|
||||
}
|
||||
|
||||
public byte get(String name, byte val) {
|
||||
@ -2641,32 +2642,32 @@ public class ObjectInputStream
|
||||
|
||||
public char get(String name, char val) {
|
||||
int off = getFieldOffset(name, Character.TYPE);
|
||||
return (off >= 0) ? Bits.getChar(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getChar(primValues, off) : val;
|
||||
}
|
||||
|
||||
public short get(String name, short val) {
|
||||
int off = getFieldOffset(name, Short.TYPE);
|
||||
return (off >= 0) ? Bits.getShort(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getShort(primValues, off) : val;
|
||||
}
|
||||
|
||||
public int get(String name, int val) {
|
||||
int off = getFieldOffset(name, Integer.TYPE);
|
||||
return (off >= 0) ? Bits.getInt(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getInt(primValues, off) : val;
|
||||
}
|
||||
|
||||
public float get(String name, float val) {
|
||||
int off = getFieldOffset(name, Float.TYPE);
|
||||
return (off >= 0) ? Bits.getFloat(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getFloat(primValues, off) : val;
|
||||
}
|
||||
|
||||
public long get(String name, long val) {
|
||||
int off = getFieldOffset(name, Long.TYPE);
|
||||
return (off >= 0) ? Bits.getLong(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getLong(primValues, off) : val;
|
||||
}
|
||||
|
||||
public double get(String name, double val) {
|
||||
int off = getFieldOffset(name, Double.TYPE);
|
||||
return (off >= 0) ? Bits.getDouble(primValues, off) : val;
|
||||
return (off >= 0) ? ByteArray.getDouble(primValues, off) : val;
|
||||
}
|
||||
|
||||
public Object get(String name, Object val) throws ClassNotFoundException {
|
||||
@ -3114,7 +3115,7 @@ public class ObjectInputStream
|
||||
return HEADER_BLOCKED;
|
||||
}
|
||||
in.readFully(hbuf, 0, 5);
|
||||
int len = Bits.getInt(hbuf, 1);
|
||||
int len = ByteArray.getInt(hbuf, 1);
|
||||
if (len < 0) {
|
||||
throw new StreamCorruptedException(
|
||||
"illegal block data header length: " +
|
||||
@ -3413,7 +3414,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 2) {
|
||||
return din.readChar();
|
||||
}
|
||||
char v = Bits.getChar(buf, pos);
|
||||
char v = ByteArray.getChar(buf, pos);
|
||||
pos += 2;
|
||||
return v;
|
||||
}
|
||||
@ -3425,7 +3426,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 2) {
|
||||
return din.readShort();
|
||||
}
|
||||
short v = Bits.getShort(buf, pos);
|
||||
short v = ByteArray.getShort(buf, pos);
|
||||
pos += 2;
|
||||
return v;
|
||||
}
|
||||
@ -3437,7 +3438,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 2) {
|
||||
return din.readUnsignedShort();
|
||||
}
|
||||
int v = Bits.getShort(buf, pos) & 0xFFFF;
|
||||
int v = ByteArray.getShort(buf, pos) & 0xFFFF;
|
||||
pos += 2;
|
||||
return v;
|
||||
}
|
||||
@ -3449,7 +3450,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 4) {
|
||||
return din.readInt();
|
||||
}
|
||||
int v = Bits.getInt(buf, pos);
|
||||
int v = ByteArray.getInt(buf, pos);
|
||||
pos += 4;
|
||||
return v;
|
||||
}
|
||||
@ -3461,7 +3462,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 4) {
|
||||
return din.readFloat();
|
||||
}
|
||||
float v = Bits.getFloat(buf, pos);
|
||||
float v = ByteArray.getFloat(buf, pos);
|
||||
pos += 4;
|
||||
return v;
|
||||
}
|
||||
@ -3473,7 +3474,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 8) {
|
||||
return din.readLong();
|
||||
}
|
||||
long v = Bits.getLong(buf, pos);
|
||||
long v = ByteArray.getLong(buf, pos);
|
||||
pos += 8;
|
||||
return v;
|
||||
}
|
||||
@ -3485,7 +3486,7 @@ public class ObjectInputStream
|
||||
} else if (end - pos < 8) {
|
||||
return din.readDouble();
|
||||
}
|
||||
double v = Bits.getDouble(buf, pos);
|
||||
double v = ByteArray.getDouble(buf, pos);
|
||||
pos += 8;
|
||||
return v;
|
||||
}
|
||||
@ -3523,7 +3524,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getBoolean(buf, pos++);
|
||||
v[off++] = ByteArray.getBoolean(buf, pos++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3544,7 +3545,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getChar(buf, pos);
|
||||
v[off++] = ByteArray.getChar(buf, pos);
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
@ -3566,7 +3567,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getShort(buf, pos);
|
||||
v[off++] = ByteArray.getShort(buf, pos);
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
@ -3588,7 +3589,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getInt(buf, pos);
|
||||
v[off++] = ByteArray.getInt(buf, pos);
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
@ -3610,7 +3611,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getFloat(buf, pos);
|
||||
v[off++] = ByteArray.getFloat(buf, pos);
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
@ -3632,7 +3633,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getLong(buf, pos);
|
||||
v[off++] = ByteArray.getLong(buf, pos);
|
||||
pos += 8;
|
||||
}
|
||||
}
|
||||
@ -3654,7 +3655,7 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
while (off < stop) {
|
||||
v[off++] = Bits.getDouble(buf, pos);
|
||||
v[off++] = ByteArray.getDouble(buf, pos);
|
||||
pos += 8;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import jdk.internal.util.ByteArray;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
@ -1638,7 +1640,7 @@ public class ObjectOutputStream
|
||||
}
|
||||
|
||||
public void put(String name, boolean val) {
|
||||
Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
|
||||
ByteArray.setBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, byte val) {
|
||||
@ -1646,27 +1648,27 @@ public class ObjectOutputStream
|
||||
}
|
||||
|
||||
public void put(String name, char val) {
|
||||
Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
|
||||
ByteArray.setChar(primVals, getFieldOffset(name, Character.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, short val) {
|
||||
Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
|
||||
ByteArray.setShort(primVals, getFieldOffset(name, Short.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, int val) {
|
||||
Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
|
||||
ByteArray.setInt(primVals, getFieldOffset(name, Integer.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, float val) {
|
||||
Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
|
||||
ByteArray.setFloat(primVals, getFieldOffset(name, Float.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, long val) {
|
||||
Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
|
||||
ByteArray.setLong(primVals, getFieldOffset(name, Long.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, double val) {
|
||||
Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
|
||||
ByteArray.setDouble(primVals, getFieldOffset(name, Double.TYPE), val);
|
||||
}
|
||||
|
||||
public void put(String name, Object val) {
|
||||
@ -1908,7 +1910,7 @@ public class ObjectOutputStream
|
||||
out.write(hbuf, 0, 2);
|
||||
} else {
|
||||
hbuf[0] = TC_BLOCKDATALONG;
|
||||
Bits.putInt(hbuf, 1, len);
|
||||
ByteArray.setInt(hbuf, 1, len);
|
||||
out.write(hbuf, 0, 5);
|
||||
}
|
||||
}
|
||||
@ -1925,7 +1927,7 @@ public class ObjectOutputStream
|
||||
if (pos >= MAX_BLOCK_SIZE) {
|
||||
drain();
|
||||
}
|
||||
Bits.putBoolean(buf, pos++, v);
|
||||
ByteArray.setBoolean(buf, pos++, v);
|
||||
}
|
||||
|
||||
public void writeByte(int v) throws IOException {
|
||||
@ -1937,7 +1939,7 @@ public class ObjectOutputStream
|
||||
|
||||
public void writeChar(int v) throws IOException {
|
||||
if (pos + 2 <= MAX_BLOCK_SIZE) {
|
||||
Bits.putChar(buf, pos, (char) v);
|
||||
ByteArray.setChar(buf, pos, (char) v);
|
||||
pos += 2;
|
||||
} else {
|
||||
dout.writeChar(v);
|
||||
@ -1946,7 +1948,7 @@ public class ObjectOutputStream
|
||||
|
||||
public void writeShort(int v) throws IOException {
|
||||
if (pos + 2 <= MAX_BLOCK_SIZE) {
|
||||
Bits.putShort(buf, pos, (short) v);
|
||||
ByteArray.setShort(buf, pos, (short) v);
|
||||
pos += 2;
|
||||
} else {
|
||||
dout.writeShort(v);
|
||||
@ -1955,7 +1957,7 @@ public class ObjectOutputStream
|
||||
|
||||
public void writeInt(int v) throws IOException {
|
||||
if (pos + 4 <= MAX_BLOCK_SIZE) {
|
||||
Bits.putInt(buf, pos, v);
|
||||
ByteArray.setInt(buf, pos, v);
|
||||
pos += 4;
|
||||
} else {
|
||||
dout.writeInt(v);
|
||||
@ -1964,7 +1966,7 @@ public class ObjectOutputStream
|
||||
|
||||
public void writeFloat(float v) throws IOException {
|
||||
if (pos + 4 <= MAX_BLOCK_SIZE) {
|
||||
Bits.putFloat(buf, pos, v);
|
||||
ByteArray.setFloat(buf, pos, v);
|
||||
pos += 4;
|
||||
} else {
|
||||
dout.writeFloat(v);
|
||||
@ -1973,7 +1975,7 @@ public class ObjectOutputStream
|
||||
|
||||
public void writeLong(long v) throws IOException {
|
||||
if (pos + 8 <= MAX_BLOCK_SIZE) {
|
||||
Bits.putLong(buf, pos, v);
|
||||
ByteArray.setLong(buf, pos, v);
|
||||
pos += 8;
|
||||
} else {
|
||||
dout.writeLong(v);
|
||||
@ -1982,7 +1984,7 @@ public class ObjectOutputStream
|
||||
|
||||
public void writeDouble(double v) throws IOException {
|
||||
if (pos + 8 <= MAX_BLOCK_SIZE) {
|
||||
Bits.putDouble(buf, pos, v);
|
||||
ByteArray.setDouble(buf, pos, v);
|
||||
pos += 8;
|
||||
} else {
|
||||
dout.writeDouble(v);
|
||||
@ -2042,7 +2044,7 @@ public class ObjectOutputStream
|
||||
}
|
||||
int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
|
||||
while (off < stop) {
|
||||
Bits.putBoolean(buf, pos++, v[off++]);
|
||||
ByteArray.setBoolean(buf, pos++, v[off++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2055,7 +2057,7 @@ public class ObjectOutputStream
|
||||
int avail = (MAX_BLOCK_SIZE - pos) >> 1;
|
||||
int stop = Math.min(endoff, off + avail);
|
||||
while (off < stop) {
|
||||
Bits.putChar(buf, pos, v[off++]);
|
||||
ByteArray.setChar(buf, pos, v[off++]);
|
||||
pos += 2;
|
||||
}
|
||||
} else {
|
||||
@ -2072,7 +2074,7 @@ public class ObjectOutputStream
|
||||
int avail = (MAX_BLOCK_SIZE - pos) >> 1;
|
||||
int stop = Math.min(endoff, off + avail);
|
||||
while (off < stop) {
|
||||
Bits.putShort(buf, pos, v[off++]);
|
||||
ByteArray.setShort(buf, pos, v[off++]);
|
||||
pos += 2;
|
||||
}
|
||||
} else {
|
||||
@ -2089,7 +2091,7 @@ public class ObjectOutputStream
|
||||
int avail = (MAX_BLOCK_SIZE - pos) >> 2;
|
||||
int stop = Math.min(endoff, off + avail);
|
||||
while (off < stop) {
|
||||
Bits.putInt(buf, pos, v[off++]);
|
||||
ByteArray.setInt(buf, pos, v[off++]);
|
||||
pos += 4;
|
||||
}
|
||||
} else {
|
||||
@ -2106,7 +2108,7 @@ public class ObjectOutputStream
|
||||
int avail = (MAX_BLOCK_SIZE - pos) >> 2;
|
||||
int stop = Math.min(endoff, off + avail);
|
||||
while (off < stop) {
|
||||
Bits.putFloat(buf, pos, v[off++]);
|
||||
ByteArray.setFloat(buf, pos, v[off++]);
|
||||
pos += 4;
|
||||
}
|
||||
} else {
|
||||
@ -2123,7 +2125,7 @@ public class ObjectOutputStream
|
||||
int avail = (MAX_BLOCK_SIZE - pos) >> 3;
|
||||
int stop = Math.min(endoff, off + avail);
|
||||
while (off < stop) {
|
||||
Bits.putLong(buf, pos, v[off++]);
|
||||
ByteArray.setLong(buf, pos, v[off++]);
|
||||
pos += 8;
|
||||
}
|
||||
} else {
|
||||
@ -2140,7 +2142,7 @@ public class ObjectOutputStream
|
||||
int avail = (MAX_BLOCK_SIZE - pos) >> 3;
|
||||
int stop = Math.min(endoff, off + avail);
|
||||
while (off < stop) {
|
||||
Bits.putDouble(buf, pos, v[off++]);
|
||||
ByteArray.setDouble(buf, pos, v[off++]);
|
||||
pos += 8;
|
||||
}
|
||||
} else {
|
||||
|
@ -61,6 +61,7 @@ import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.access.JavaSecurityAccess;
|
||||
import jdk.internal.util.ByteArray;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
@ -1986,14 +1987,14 @@ public final class ObjectStreamClass implements Serializable {
|
||||
long key = readKeys[i];
|
||||
int off = offsets[i];
|
||||
switch (typeCodes[i]) {
|
||||
case 'Z' -> Bits.putBoolean(buf, off, UNSAFE.getBoolean(obj, key));
|
||||
case 'Z' -> ByteArray.setBoolean(buf, off, UNSAFE.getBoolean(obj, key));
|
||||
case 'B' -> buf[off] = UNSAFE.getByte(obj, key);
|
||||
case 'C' -> Bits.putChar(buf, off, UNSAFE.getChar(obj, key));
|
||||
case 'S' -> Bits.putShort(buf, off, UNSAFE.getShort(obj, key));
|
||||
case 'I' -> Bits.putInt(buf, off, UNSAFE.getInt(obj, key));
|
||||
case 'F' -> Bits.putFloat(buf, off, UNSAFE.getFloat(obj, key));
|
||||
case 'J' -> Bits.putLong(buf, off, UNSAFE.getLong(obj, key));
|
||||
case 'D' -> Bits.putDouble(buf, off, UNSAFE.getDouble(obj, key));
|
||||
case 'C' -> ByteArray.setChar(buf, off, UNSAFE.getChar(obj, key));
|
||||
case 'S' -> ByteArray.setShort(buf, off, UNSAFE.getShort(obj, key));
|
||||
case 'I' -> ByteArray.setInt(buf, off, UNSAFE.getInt(obj, key));
|
||||
case 'F' -> ByteArray.setFloat(buf, off, UNSAFE.getFloat(obj, key));
|
||||
case 'J' -> ByteArray.setLong(buf, off, UNSAFE.getLong(obj, key));
|
||||
case 'D' -> ByteArray.setDouble(buf, off, UNSAFE.getDouble(obj, key));
|
||||
default -> throw new InternalError();
|
||||
}
|
||||
}
|
||||
@ -2015,14 +2016,14 @@ public final class ObjectStreamClass implements Serializable {
|
||||
}
|
||||
int off = offsets[i];
|
||||
switch (typeCodes[i]) {
|
||||
case 'Z' -> UNSAFE.putBoolean(obj, key, Bits.getBoolean(buf, off));
|
||||
case 'Z' -> UNSAFE.putBoolean(obj, key, ByteArray.getBoolean(buf, off));
|
||||
case 'B' -> UNSAFE.putByte(obj, key, buf[off]);
|
||||
case 'C' -> UNSAFE.putChar(obj, key, Bits.getChar(buf, off));
|
||||
case 'S' -> UNSAFE.putShort(obj, key, Bits.getShort(buf, off));
|
||||
case 'I' -> UNSAFE.putInt(obj, key, Bits.getInt(buf, off));
|
||||
case 'F' -> UNSAFE.putFloat(obj, key, Bits.getFloat(buf, off));
|
||||
case 'J' -> UNSAFE.putLong(obj, key, Bits.getLong(buf, off));
|
||||
case 'D' -> UNSAFE.putDouble(obj, key, Bits.getDouble(buf, off));
|
||||
case 'C' -> UNSAFE.putChar(obj, key, ByteArray.getChar(buf, off));
|
||||
case 'S' -> UNSAFE.putShort(obj, key, ByteArray.getShort(buf, off));
|
||||
case 'I' -> UNSAFE.putInt(obj, key, ByteArray.getInt(buf, off));
|
||||
case 'F' -> UNSAFE.putFloat(obj, key, ByteArray.getFloat(buf, off));
|
||||
case 'J' -> UNSAFE.putLong(obj, key, ByteArray.getLong(buf, off));
|
||||
case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
|
||||
default -> throw new InternalError();
|
||||
}
|
||||
}
|
||||
@ -2473,16 +2474,16 @@ public final class ObjectStreamClass implements Serializable {
|
||||
try {
|
||||
PRIM_VALUE_EXTRACTORS = Map.of(
|
||||
byte.class, MethodHandles.arrayElementGetter(byte[].class),
|
||||
short.class, lkp.findStatic(Bits.class, "getShort", MethodType.methodType(short.class, byte[].class, int.class)),
|
||||
int.class, lkp.findStatic(Bits.class, "getInt", MethodType.methodType(int.class, byte[].class, int.class)),
|
||||
long.class, lkp.findStatic(Bits.class, "getLong", MethodType.methodType(long.class, byte[].class, int.class)),
|
||||
float.class, lkp.findStatic(Bits.class, "getFloat", MethodType.methodType(float.class, byte[].class, int.class)),
|
||||
double.class, lkp.findStatic(Bits.class, "getDouble", MethodType.methodType(double.class, byte[].class, int.class)),
|
||||
char.class, lkp.findStatic(Bits.class, "getChar", MethodType.methodType(char.class, byte[].class, int.class)),
|
||||
boolean.class, lkp.findStatic(Bits.class, "getBoolean", MethodType.methodType(boolean.class, byte[].class, int.class))
|
||||
short.class, lkp.findStatic(ByteArray.class, "getShort", MethodType.methodType(short.class, byte[].class, int.class)),
|
||||
int.class, lkp.findStatic(ByteArray.class, "getInt", MethodType.methodType(int.class, byte[].class, int.class)),
|
||||
long.class, lkp.findStatic(ByteArray.class, "getLong", MethodType.methodType(long.class, byte[].class, int.class)),
|
||||
float.class, lkp.findStatic(ByteArray.class, "getFloat", MethodType.methodType(float.class, byte[].class, int.class)),
|
||||
double.class, lkp.findStatic(ByteArray.class, "getDouble", MethodType.methodType(double.class, byte[].class, int.class)),
|
||||
char.class, lkp.findStatic(ByteArray.class, "getChar", MethodType.methodType(char.class, byte[].class, int.class)),
|
||||
boolean.class, lkp.findStatic(ByteArray.class, "getBoolean", MethodType.methodType(boolean.class, byte[].class, int.class))
|
||||
);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new InternalError("Can't lookup Bits.getXXX", e);
|
||||
throw new InternalError("Can't lookup " + ByteArray.class.getName() + ".getXXX", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,6 +30,7 @@ import java.nio.channels.FileChannel;
|
||||
import jdk.internal.access.JavaIORandomAccessFileAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.Blocker;
|
||||
import jdk.internal.util.ByteArray;
|
||||
import sun.nio.ch.FileChannelImpl;
|
||||
|
||||
|
||||
@ -884,7 +885,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
*/
|
||||
public final int readInt() throws IOException {
|
||||
readFully(buffer, 0, Integer.BYTES);
|
||||
return Bits.getInt(buffer, 0);
|
||||
return ByteArray.getInt(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -917,7 +918,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
*/
|
||||
public final long readLong() throws IOException {
|
||||
readFully(buffer, 0, Long.BYTES);
|
||||
return Bits.getLong(buffer, 0);
|
||||
return ByteArray.getLong(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -941,7 +942,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
*/
|
||||
public final float readFloat() throws IOException {
|
||||
readFully(buffer, 0, Float.BYTES);
|
||||
return Bits.getFloat(buffer, 0);
|
||||
return ByteArray.getFloat(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -965,7 +966,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
*/
|
||||
public final double readDouble() throws IOException {
|
||||
readFully(buffer, 0, Double.BYTES);
|
||||
return Bits.getDouble(buffer, 0);
|
||||
return ByteArray.getDouble(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1104,7 +1105,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public final void writeInt(int v) throws IOException {
|
||||
Bits.putInt(buffer, 0, v);
|
||||
ByteArray.setInt(buffer, 0, v);
|
||||
write(buffer, 0, Integer.BYTES);
|
||||
//written += 4;
|
||||
}
|
||||
@ -1117,7 +1118,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public final void writeLong(long v) throws IOException {
|
||||
Bits.putLong(buffer, 0, v);
|
||||
ByteArray.setLong(buffer, 0, v);
|
||||
write(buffer, 0, Long.BYTES);
|
||||
}
|
||||
|
||||
@ -1133,7 +1134,8 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
* @see java.lang.Float#floatToIntBits(float)
|
||||
*/
|
||||
public final void writeFloat(float v) throws IOException {
|
||||
writeInt(Float.floatToIntBits(v));
|
||||
ByteArray.setFloat(buffer, 0, v);
|
||||
write(buffer, 0, Float.BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1148,7 +1150,8 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
* @see java.lang.Double#doubleToLongBits(double)
|
||||
*/
|
||||
public final void writeDouble(double v) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(v));
|
||||
ByteArray.setDouble(buffer, 0, v);
|
||||
write(buffer, 0, Double.BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
|
424
src/java.base/share/classes/jdk/internal/util/ByteArray.java
Normal file
424
src/java.base/share/classes/jdk/internal/util/ByteArray.java
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.internal.util;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Utility methods for packing/unpacking primitive values in/out of byte arrays
|
||||
* using {@linkplain ByteOrder#BIG_ENDIAN big endian order} (aka. "network order").
|
||||
* <p>
|
||||
* All methods in this class will throw an {@linkplain NullPointerException} if {@code null} is
|
||||
* passed in as a method parameter for a byte array.
|
||||
*/
|
||||
public final class ByteArray {
|
||||
|
||||
private ByteArray() {
|
||||
}
|
||||
|
||||
private static final VarHandle SHORT = create(short[].class);
|
||||
private static final VarHandle CHAR = create(char[].class);
|
||||
private static final VarHandle INT = create(int[].class);
|
||||
private static final VarHandle FLOAT = create(float[].class);
|
||||
private static final VarHandle LONG = create(long[].class);
|
||||
private static final VarHandle DOUBLE = create(double[].class);
|
||||
|
||||
/*
|
||||
* Methods for unpacking primitive values from byte arrays starting at
|
||||
* a given offset.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@return a {@code boolean} from the provided {@code array} at the given {@code offset}}.
|
||||
*
|
||||
* @param array to read a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 1]
|
||||
* @see #setBoolean(byte[], int, boolean)
|
||||
*/
|
||||
public static boolean getBoolean(byte[] array, int offset) {
|
||||
return array[offset] != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code char} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #setChar(byte[], int, char)
|
||||
*/
|
||||
public static char getChar(byte[] array, int offset) {
|
||||
return (char) CHAR.get(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code short} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @return a {@code short} from the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #setShort(byte[], int, short)
|
||||
*/
|
||||
public static short getShort(byte[] array, int offset) {
|
||||
return (short) SHORT.get(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return an {@code unsigned short} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @return an {@code int} representing an unsigned short from the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #setUnsignedShort(byte[], int, int)
|
||||
*/
|
||||
public static int getUnsignedShort(byte[] array, int offset) {
|
||||
return Short.toUnsignedInt((short) SHORT.get(array, offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return an {@code int} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 4]
|
||||
* @see #setInt(byte[], int, int)
|
||||
*/
|
||||
public static int getInt(byte[] array, int offset) {
|
||||
return (int) INT.get(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code float} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Float#NaN } values are canonized to a single NaN value.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 4]
|
||||
* @see #setFloat(byte[], int, float)
|
||||
*/
|
||||
public static float getFloat(byte[] array, int offset) {
|
||||
// Using Float.intBitsToFloat collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
return Float.intBitsToFloat((int) INT.get(array, offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code float} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Float#NaN } values are silently read according
|
||||
* to their bit patterns.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 4]
|
||||
* @see #setFloatRaw(byte[], int, float)
|
||||
*/
|
||||
public static float getFloatRaw(byte[] array, int offset) {
|
||||
// Just gets the bits as they are
|
||||
return (float) FLOAT.get(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code long} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 8]
|
||||
* @see #setLong(byte[], int, long)
|
||||
*/
|
||||
public static long getLong(byte[] array, int offset) {
|
||||
return (long) LONG.get(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code double} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Double#NaN } values are canonized to a single NaN value.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 8]
|
||||
* @see #setDouble(byte[], int, double)
|
||||
*/
|
||||
public static double getDouble(byte[] array, int offset) {
|
||||
// Using Double.longBitsToDouble collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
return Double.longBitsToDouble((long) LONG.get(array, offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code double} from the provided {@code array} at the given {@code offset}
|
||||
* using big endian order}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Double#NaN } values are silently read according to
|
||||
* their bit patterns.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to get a value from.
|
||||
* @param offset where extraction in the array should begin
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 8]
|
||||
* @see #setDoubleRaw(byte[], int, double)
|
||||
*/
|
||||
public static double getDoubleRaw(byte[] array, int offset) {
|
||||
// Just gets the bits as they are
|
||||
return (double) DOUBLE.get(array, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods for packing primitive values into byte arrays starting at a given
|
||||
* offset.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length]
|
||||
* @see #getBoolean(byte[], int)
|
||||
*/
|
||||
public static void setBoolean(byte[] array, int offset, boolean value) {
|
||||
array[offset] = (byte) (value ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getChar(byte[], int)
|
||||
*/
|
||||
public static void setChar(byte[] array, int offset, char value) {
|
||||
CHAR.set(array, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getShort(byte[], int)
|
||||
*/
|
||||
public static void setShort(byte[] array, int offset, short value) {
|
||||
SHORT.set(array, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getUnsignedShort(byte[], int)
|
||||
*/
|
||||
public static void setUnsignedShort(byte[] array, int offset, int value) {
|
||||
SHORT.set(array, offset, (short) (char) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 4]
|
||||
* @see #getInt(byte[], int)
|
||||
*/
|
||||
public static void setInt(byte[] array, int offset, int value) {
|
||||
INT.set(array, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Float#NaN } values are canonized to a single NaN value.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getFloat(byte[], int)
|
||||
*/
|
||||
public static void setFloat(byte[] array, int offset, float value) {
|
||||
// Using Float.floatToIntBits collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
INT.set(array, offset, Float.floatToIntBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Float#NaN } values are silently written according to
|
||||
* their bit patterns.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getFloatRaw(byte[], int)
|
||||
*/
|
||||
public static void setFloatRaw(byte[] array, int offset, float value) {
|
||||
// Just sets the bits as they are
|
||||
FLOAT.set(array, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 4]
|
||||
* @see #getLong(byte[], int)
|
||||
*/
|
||||
public static void setLong(byte[] array, int offset, long value) {
|
||||
LONG.set(array, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Double#NaN } values are canonized to a single NaN value.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getDouble(byte[], int)
|
||||
*/
|
||||
public static void setDouble(byte[] array, int offset, double value) {
|
||||
// Using Double.doubleToLongBits collapses NaN values to a single
|
||||
// "canonical" NaN value
|
||||
LONG.set(array, offset, Double.doubleToLongBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (writes) the provided {@code value} using big endian order into
|
||||
* the provided {@code array} beginning at the given {@code offset}.
|
||||
* <p>
|
||||
* Variants of {@linkplain Double#NaN } values are silently written according to
|
||||
* their bit patterns.
|
||||
* <p>
|
||||
* There are no access alignment requirements.
|
||||
*
|
||||
* @param array to set (write) a value into
|
||||
* @param offset where setting (writing) in the array should begin
|
||||
* @param value value to set in the array
|
||||
* @throws IndexOutOfBoundsException if the provided {@code offset} is outside
|
||||
* the range [0, array.length - 2]
|
||||
* @see #getDoubleRaw(byte[], int)
|
||||
*/
|
||||
public static void setDoubleRaw(byte[] array, int offset, double value) {
|
||||
// Just sets the bits as they are
|
||||
DOUBLE.set(array, offset, value);
|
||||
}
|
||||
|
||||
private static VarHandle create(Class<?> viewArrayClass) {
|
||||
return MethodHandles.byteArrayViewVarHandle(viewArrayClass, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
/**
|
||||
* Class to allow public access to package-private methods.
|
||||
*/
|
||||
public final class BitsProxy {
|
||||
|
||||
public static boolean getBoolean(byte[] b, int off) {
|
||||
return Bits.getBoolean(b, off);
|
||||
}
|
||||
|
||||
public static char getChar(byte[] b, int off) {
|
||||
return Bits.getChar(b, off);
|
||||
}
|
||||
|
||||
public static short getShort(byte[] b, int off) {
|
||||
return Bits.getShort(b, off);
|
||||
}
|
||||
|
||||
public static int getInt(byte[] b, int off) {
|
||||
return Bits.getInt(b, off);
|
||||
}
|
||||
|
||||
public static float getFloat(byte[] b, int off) {
|
||||
return Bits.getFloat(b, off);
|
||||
}
|
||||
|
||||
public static long getLong(byte[] b, int off) {
|
||||
return Bits.getLong(b, off);
|
||||
}
|
||||
|
||||
public static double getDouble(byte[] b, int off) {
|
||||
return Bits.getDouble(b, off);
|
||||
}
|
||||
|
||||
|
||||
public static void putBoolean(byte[] b, int off, boolean val) {
|
||||
Bits.putBoolean(b, off, val);
|
||||
}
|
||||
|
||||
public static void putChar(byte[] b, int off, char val) {
|
||||
Bits.putChar(b, off, val);
|
||||
}
|
||||
|
||||
public static void putShort(byte[] b, int off, short val) {
|
||||
Bits.putShort(b, off, val);
|
||||
}
|
||||
|
||||
public static void putInt(byte[] b, int off, int val) {
|
||||
Bits.putInt(b, off, val);
|
||||
}
|
||||
|
||||
public static void putFloat(byte[] b, int off, float val) {
|
||||
Bits.putFloat(b, off, val);
|
||||
}
|
||||
|
||||
public static void putLong(byte[] b, int off, long val) {
|
||||
Bits.putLong(b, off, val);
|
||||
}
|
||||
|
||||
public static void putDouble(byte[] b, int off, double val) {
|
||||
Bits.putDouble(b, off, val);
|
||||
}
|
||||
|
||||
}
|
@ -24,19 +24,19 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8299576
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that reads and writes of primitives are correct
|
||||
* @compile/module=java.base java/io/BitsProxy.java
|
||||
* @run junit ReadWriteValues
|
||||
*/
|
||||
|
||||
import java.io.BitsProxy;
|
||||
import jdk.internal.util.ByteArray;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.DoubleStream;
|
||||
import java.util.stream.LongStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
final class ReadWriteValues {
|
||||
@ -53,7 +53,7 @@ final class ReadWriteValues {
|
||||
longs().forEach(l -> {
|
||||
short expected = (short) l;
|
||||
RefImpl.putShort(BUFF, OFFSET, expected);
|
||||
short actual = BitsProxy.getShort(BUFF, OFFSET);
|
||||
short actual = ByteArray.getShort(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
@ -62,7 +62,7 @@ final class ReadWriteValues {
|
||||
void testPutShort() {
|
||||
longs().forEach(l -> {
|
||||
short expected = (short) l;
|
||||
BitsProxy.putShort(BUFF, OFFSET, expected);
|
||||
ByteArray.setShort(BUFF, OFFSET, expected);
|
||||
short actual = RefImpl.getShort(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
@ -73,7 +73,7 @@ final class ReadWriteValues {
|
||||
longs().forEach(l -> {
|
||||
char expected = (char) l;
|
||||
RefImpl.putChar(BUFF, OFFSET, expected);
|
||||
char actual = BitsProxy.getChar(BUFF, OFFSET);
|
||||
char actual = ByteArray.getChar(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
@ -82,7 +82,7 @@ final class ReadWriteValues {
|
||||
void testPutChar() {
|
||||
longs().forEach(l -> {
|
||||
char expected = (char) l;
|
||||
BitsProxy.putChar(BUFF, OFFSET, expected);
|
||||
ByteArray.setChar(BUFF, OFFSET, expected);
|
||||
char actual = RefImpl.getChar(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
@ -93,7 +93,7 @@ final class ReadWriteValues {
|
||||
longs().forEach(l -> {
|
||||
int expected = (int) l;
|
||||
RefImpl.putInt(BUFF, OFFSET, expected);
|
||||
int actual = BitsProxy.getInt(BUFF, OFFSET);
|
||||
int actual = ByteArray.getInt(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
@ -102,7 +102,7 @@ final class ReadWriteValues {
|
||||
void testPutInt() {
|
||||
longs().forEach(l -> {
|
||||
int expected = (int) l;
|
||||
BitsProxy.putInt(BUFF, OFFSET, expected);
|
||||
ByteArray.setInt(BUFF, OFFSET, expected);
|
||||
int actual = RefImpl.getInt(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
@ -112,7 +112,7 @@ final class ReadWriteValues {
|
||||
void testGetLong() {
|
||||
longs().forEach(expected -> {
|
||||
RefImpl.putLong(BUFF, OFFSET, expected);
|
||||
long actual = BitsProxy.getLong(BUFF, OFFSET);
|
||||
long actual = ByteArray.getLong(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
@ -120,7 +120,7 @@ final class ReadWriteValues {
|
||||
@Test
|
||||
void testPutLong() {
|
||||
longs().forEach(expected -> {
|
||||
BitsProxy.putLong(BUFF, OFFSET, expected);
|
||||
ByteArray.setLong(BUFF, OFFSET, expected);
|
||||
long actual = RefImpl.getLong(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
@ -130,7 +130,7 @@ final class ReadWriteValues {
|
||||
void testGetFloat() {
|
||||
floats().forEach(expected -> {
|
||||
RefImpl.putFloat(BUFF, OFFSET, expected);
|
||||
float actual = BitsProxy.getFloat(BUFF, OFFSET);
|
||||
float actual = ByteArray.getFloat(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
@ -138,7 +138,7 @@ final class ReadWriteValues {
|
||||
@Test
|
||||
void testPutFloat() {
|
||||
floats().forEach(expected -> {
|
||||
BitsProxy.putFloat(BUFF, OFFSET, expected);
|
||||
ByteArray.setFloat(BUFF, OFFSET, expected);
|
||||
float actual = RefImpl.getFloat(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
@ -148,7 +148,7 @@ final class ReadWriteValues {
|
||||
void testGetDouble() {
|
||||
doubles().forEach(expected -> {
|
||||
RefImpl.putDouble(BUFF, OFFSET, expected);
|
||||
double actual = BitsProxy.getDouble(BUFF, OFFSET);
|
||||
double actual = ByteArray.getDouble(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
@ -156,31 +156,183 @@ final class ReadWriteValues {
|
||||
@Test
|
||||
void testPutDouble() {
|
||||
doubles().forEach(expected -> {
|
||||
BitsProxy.putDouble(BUFF, OFFSET, expected);
|
||||
ByteArray.setDouble(BUFF, OFFSET, expected);
|
||||
double actual = RefImpl.getDouble(BUFF, OFFSET);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutUnsignedShort() {
|
||||
longs().forEach(l -> {
|
||||
int expected = Short.toUnsignedInt((short) l);
|
||||
ByteArray.setUnsignedShort(BUFF, OFFSET, expected);
|
||||
int actual = Short.toUnsignedInt(RefImpl.getShort(BUFF, OFFSET));
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Unusual cases
|
||||
|
||||
@Test
|
||||
void testNullArray() {
|
||||
assertThrowsOriginal(NullPointerException.class, () -> ByteArray.getInt(null, OFFSET));
|
||||
assertThrowsOriginal(NullPointerException.class, () -> ByteArray.setInt(null, OFFSET, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNegArg() {
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.getInt(BUFF, -1));
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.setInt(BUFF, -1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOutOfBounds() {
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.getInt(BUFF, BUFF.length));
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.setInt(BUFF, BUFF.length, 1));
|
||||
}
|
||||
|
||||
// At-zero methods
|
||||
|
||||
@Test
|
||||
void testGetShortAtZero() {
|
||||
longs().forEach(l -> {
|
||||
short expected = (short) l;
|
||||
RefImpl.putShort(BUFF, 0, expected);
|
||||
short actual = ByteArray.getShort(BUFF);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutShortAtZero() {
|
||||
longs().forEach(l -> {
|
||||
short expected = (short) l;
|
||||
ByteArray.setShort(BUFF, expected);
|
||||
short actual = RefImpl.getShort(BUFF, 0);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetCharAtZero() {
|
||||
longs().forEach(l -> {
|
||||
char expected = (char) l;
|
||||
RefImpl.putChar(BUFF, 0, expected);
|
||||
char actual = ByteArray.getChar(BUFF);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutCharAtZero() {
|
||||
longs().forEach(l -> {
|
||||
char expected = (char) l;
|
||||
ByteArray.setChar(BUFF, expected);
|
||||
char actual = RefImpl.getChar(BUFF, 0);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetIntAtZero() {
|
||||
longs().forEach(l -> {
|
||||
int expected = (int) l;
|
||||
RefImpl.putInt(BUFF, 0, expected);
|
||||
int actual = ByteArray.getInt(BUFF);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutIntAtZero() {
|
||||
longs().forEach(l -> {
|
||||
int expected = (int) l;
|
||||
ByteArray.setInt(BUFF, expected);
|
||||
int actual = RefImpl.getInt(BUFF, 0);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLongAtZero() {
|
||||
longs().forEach(expected -> {
|
||||
RefImpl.putLong(BUFF, 0, expected);
|
||||
long actual = ByteArray.getLong(BUFF);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutLongAtZero() {
|
||||
longs().forEach(expected -> {
|
||||
ByteArray.setLong(BUFF, expected);
|
||||
long actual = RefImpl.getLong(BUFF, 0);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFloatAtZero() {
|
||||
floats().forEach(expected -> {
|
||||
RefImpl.putFloat(BUFF, 0, expected);
|
||||
float actual = ByteArray.getFloat(BUFF);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutFloatAtZero() {
|
||||
floats().forEach(expected -> {
|
||||
ByteArray.setFloat(BUFF, expected);
|
||||
float actual = RefImpl.getFloat(BUFF, 0);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDoubleAtZero() {
|
||||
doubles().forEach(expected -> {
|
||||
RefImpl.putDouble(BUFF, 0, expected);
|
||||
double actual = ByteArray.getDouble(BUFF);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutDoubleAtZero() {
|
||||
doubles().forEach(expected -> {
|
||||
ByteArray.setDouble(BUFF, expected);
|
||||
double actual = RefImpl.getDouble(BUFF, 0);
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPutUnsignedShortAtZero() {
|
||||
longs().forEach(l -> {
|
||||
int expected = Short.toUnsignedInt((short) l);
|
||||
ByteArray.setUnsignedShort(BUFF, expected);
|
||||
int actual = Short.toUnsignedInt(RefImpl.getShort(BUFF, 0));
|
||||
assertEquals(expected, actual);
|
||||
});
|
||||
}
|
||||
|
||||
// Unusual cases
|
||||
|
||||
@Test
|
||||
void testNullArray() {
|
||||
assertThrowsOriginal(NullPointerException.class, () -> BitsProxy.getInt(null, OFFSET));
|
||||
assertThrowsOriginal(NullPointerException.class, () -> BitsProxy.putInt(null, OFFSET, 1));
|
||||
void testNullArrayAtZero() {
|
||||
assertThrowsOriginal(NullPointerException.class, () -> ByteArray.getInt(null));
|
||||
assertThrowsOriginal(NullPointerException.class, () -> ByteArray.setInt(null, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNegArg() {
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> BitsProxy.getInt(BUFF, -1));
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> BitsProxy.putInt(BUFF, -1, 1));
|
||||
void testOutOfBoundsAtZero() {
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.getInt(new byte[1]));
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> ByteArray.setInt(new byte[1],1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOutOfBounds() {
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> BitsProxy.getInt(BUFF, BUFF.length));
|
||||
assertThrowsOriginal(IndexOutOfBoundsException.class, () -> BitsProxy.putInt(BUFF, BUFF.length, 1));
|
||||
}
|
||||
|
||||
static LongStream longs() {
|
||||
return ThreadLocalRandom.current().longs(ITERATIONS);
|
||||
@ -315,5 +467,4 @@ final class ReadWriteValues {
|
||||
putLong(b, off, Double.doubleToLongBits(val));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.openjdk.bench.java.io;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.TearDown;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Fork(2)
|
||||
@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@State(Scope.Thread)
|
||||
|
||||
public class PrimitiveFieldSerializationBenchmark {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
Options options = new OptionsBuilder()
|
||||
.include(PrimitiveFieldSerializationBenchmark.class.getSimpleName())
|
||||
.build();
|
||||
new Runner(options).run();
|
||||
}
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public static class Log {
|
||||
|
||||
MyData myData = new MyData((byte) 1, 'a', (short) 47, 1234, 0.01f, 1234L, 0.01d);
|
||||
MyRecord myRecord = new MyRecord((byte) 1, 'a', (short) 47, 1234, 0.01f, 1234L, 0.01d);
|
||||
}
|
||||
|
||||
private OutputStream bos;
|
||||
private ObjectOutputStream os;
|
||||
|
||||
@Setup
|
||||
public void setupStreams(Blackhole bh) throws IOException {
|
||||
bos = new BlackholeOutputStream(bh);
|
||||
os = new ObjectOutputStream(bos);
|
||||
}
|
||||
|
||||
@TearDown
|
||||
public void tearDownStreams() throws IOException {
|
||||
os.close();
|
||||
bos.close();
|
||||
}
|
||||
|
||||
private static final class MyData implements Serializable {
|
||||
byte b;
|
||||
char c;
|
||||
short s;
|
||||
int i;
|
||||
float f;
|
||||
long l;
|
||||
double d;
|
||||
|
||||
public MyData(byte b, char c, short s, int i, float f, long l, double d) {
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
this.s = s;
|
||||
this.i = i;
|
||||
this.f = f;
|
||||
this.l = l;
|
||||
this.d = d;
|
||||
}
|
||||
}
|
||||
|
||||
private record MyRecord(byte b,
|
||||
char c,
|
||||
short s,
|
||||
int i,
|
||||
float f,
|
||||
long l,
|
||||
double d) implements Serializable {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void serializeData(Log input) throws IOException {
|
||||
os.writeObject(input.myData);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void serializeRecord(Log input) throws IOException {
|
||||
os.writeObject(input.myRecord);
|
||||
}
|
||||
|
||||
public static final class BlackholeOutputStream extends OutputStream {
|
||||
|
||||
private final Blackhole bh;
|
||||
|
||||
public BlackholeOutputStream(Blackhole bh) {
|
||||
this.bh = bh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
bh.consume(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) {
|
||||
bh.consume(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
bh.consume(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user