8300235: Use VarHandle access in Image(Input | Output)StreamImpl classes

Reviewed-by: rriggs
This commit is contained in:
Per Minborg 2023-02-03 07:24:20 +00:00
parent 406021ad58
commit b504c9411e
6 changed files with 624 additions and 249 deletions

View 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#LITTLE_ENDIAN little endian 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 ByteArrayLittleEndian {
private ByteArrayLittleEndian() {
}
private static final VarHandle SHORT = createLittleEndian(short[].class);
private static final VarHandle CHAR = createLittleEndian(char[].class);
private static final VarHandle INT = createLittleEndian(int[].class);
private static final VarHandle FLOAT = createLittleEndian(float[].class);
private static final VarHandle LONG = createLittleEndian(long[].class);
private static final VarHandle DOUBLE = createLittleEndian(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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 little 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 createLittleEndian(Class<?> viewArrayClass) {
return MethodHandles.byteArrayViewVarHandle(viewArrayClass, ByteOrder.LITTLE_ENDIAN);
}
}

View File

@ -272,6 +272,8 @@ module java.base {
jdk.jfr;
exports jdk.internal.util.random to
jdk.random;
exports jdk.internal.util to
java.desktop;
exports sun.net to
java.net.http,
jdk.naming.dns;

View File

@ -25,6 +25,9 @@
package javax.imageio.stream;
import jdk.internal.util.ByteArray;
import jdk.internal.util.ByteArrayLittleEndian;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
@ -43,9 +46,9 @@ import javax.imageio.IIOException;
*/
public abstract class ImageInputStreamImpl implements ImageInputStream {
private Stack<Long> markByteStack = new Stack<>();
private final Stack<Long> markByteStack = new Stack<>();
private Stack<Integer> markBitStack = new Stack<>();
private final Stack<Integer> markBitStack = new Stack<>();
private boolean isClosed = false;
@ -240,14 +243,9 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
if (read(byteBuf, 0, 2) != 2) {
throw new EOFException();
}
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return (short)
(((byteBuf[0] & 0xff) << 8) | ((byteBuf[1] & 0xff) << 0));
} else {
return (short)
(((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
}
return (byteOrder == ByteOrder.BIG_ENDIAN)
? ByteArray.getShort(byteBuf, 0)
: ByteArrayLittleEndian.getShort(byteBuf, 0);
}
/**
@ -272,15 +270,9 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
throw new EOFException();
}
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return
(((byteBuf[0] & 0xff) << 24) | ((byteBuf[1] & 0xff) << 16) |
((byteBuf[2] & 0xff) << 8) | ((byteBuf[3] & 0xff) << 0));
} else {
return
(((byteBuf[3] & 0xff) << 24) | ((byteBuf[2] & 0xff) << 16) |
((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
}
return (byteOrder == ByteOrder.BIG_ENDIAN)
? ByteArray.getInt(byteBuf, 0)
: ByteArrayLittleEndian.getInt(byteBuf, 0);
}
/**
@ -522,16 +514,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
s[off + j] = (short)((b0 << 8) | b1);
s[off + j] = ByteArray.getShort(b, boff);
boff += 2;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 1];
int b1 = b[boff] & 0xff;
s[off + j] = (short)((b0 << 8) | b1);
s[off + j] = ByteArrayLittleEndian.getShort(b, boff);
boff += 2;
}
}
@ -541,16 +529,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
c[off + j] = (char)((b0 << 8) | b1);
c[off + j] = ByteArray.getChar(b, boff);
boff += 2;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 1];
int b1 = b[boff] & 0xff;
c[off + j] = (char)((b0 << 8) | b1);
c[off + j] = ByteArrayLittleEndian.getChar(b, boff);
boff += 2;
}
}
@ -560,20 +544,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
i[off + j] = ByteArray.getInt(b, boff);
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 3];
int b1 = b[boff + 2] & 0xff;
int b2 = b[boff + 1] & 0xff;
int b3 = b[boff] & 0xff;
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
i[off + j] = ByteArrayLittleEndian.getInt(b, boff);
boff += 4;
}
}
@ -583,36 +559,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int b4 = b[boff + 4];
int b5 = b[boff + 5] & 0xff;
int b6 = b[boff + 6] & 0xff;
int b7 = b[boff + 7] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
l[off + j] = ByteArray.getLong(b, boff);
boff += 8;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 7];
int b1 = b[boff + 6] & 0xff;
int b2 = b[boff + 5] & 0xff;
int b3 = b[boff + 4] & 0xff;
int b4 = b[boff + 3];
int b5 = b[boff + 2] & 0xff;
int b6 = b[boff + 1] & 0xff;
int b7 = b[boff] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
l[off + j] = ByteArrayLittleEndian.getLong(b, boff);
boff += 8;
}
}
@ -622,22 +574,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
f[off + j] = Float.intBitsToFloat(i);
f[off + j] = ByteArray.getFloat(b, boff);
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 3];
int b1 = b[boff + 2] & 0xff;
int b2 = b[boff + 1] & 0xff;
int b3 = b[boff + 0] & 0xff;
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
f[off + j] = Float.intBitsToFloat(i);
f[off + j] = ByteArrayLittleEndian.getFloat(b, boff);
boff += 4;
}
}
@ -647,38 +589,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int b4 = b[boff + 4];
int b5 = b[boff + 5] & 0xff;
int b6 = b[boff + 6] & 0xff;
int b7 = b[boff + 7] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
d[off + j] = Double.longBitsToDouble(l);
d[off + j] = ByteArray.getDouble(b, boff);
boff += 8;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 7];
int b1 = b[boff + 6] & 0xff;
int b2 = b[boff + 5] & 0xff;
int b3 = b[boff + 4] & 0xff;
int b4 = b[boff + 3];
int b5 = b[boff + 2] & 0xff;
int b6 = b[boff + 1] & 0xff;
int b7 = b[boff] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
d[off + j] = Double.longBitsToDouble(l);
d[off + j] = ByteArrayLittleEndian.getDouble(b, boff);
boff += 8;
}
}

View File

@ -25,6 +25,9 @@
package javax.imageio.stream;
import jdk.internal.util.ByteArray;
import jdk.internal.util.ByteArrayLittleEndian;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.nio.ByteOrder;
@ -63,11 +66,9 @@ public abstract class ImageOutputStreamImpl
public void writeShort(int v) throws IOException {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
byteBuf[0] = (byte)(v >>> 8);
byteBuf[1] = (byte)(v >>> 0);
ByteArray.setUnsignedShort(byteBuf, 0, v);
} else {
byteBuf[0] = (byte)(v >>> 0);
byteBuf[1] = (byte)(v >>> 8);
ByteArrayLittleEndian.setUnsignedShort(byteBuf, 0, v);
}
write(byteBuf, 0, 2);
}
@ -78,38 +79,18 @@ public abstract class ImageOutputStreamImpl
public void writeInt(int v) throws IOException {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
byteBuf[0] = (byte)(v >>> 24);
byteBuf[1] = (byte)(v >>> 16);
byteBuf[2] = (byte)(v >>> 8);
byteBuf[3] = (byte)(v >>> 0);
ByteArray.setInt(byteBuf, 0, v);
} else {
byteBuf[0] = (byte)(v >>> 0);
byteBuf[1] = (byte)(v >>> 8);
byteBuf[2] = (byte)(v >>> 16);
byteBuf[3] = (byte)(v >>> 24);
ByteArrayLittleEndian.setInt(byteBuf, 0, v);
}
write(byteBuf, 0, 4);
}
public void writeLong(long v) throws IOException {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
byteBuf[0] = (byte)(v >>> 56);
byteBuf[1] = (byte)(v >>> 48);
byteBuf[2] = (byte)(v >>> 40);
byteBuf[3] = (byte)(v >>> 32);
byteBuf[4] = (byte)(v >>> 24);
byteBuf[5] = (byte)(v >>> 16);
byteBuf[6] = (byte)(v >>> 8);
byteBuf[7] = (byte)(v >>> 0);
ByteArray.setLong(byteBuf, 0, v);
} else {
byteBuf[0] = (byte)(v >>> 0);
byteBuf[1] = (byte)(v >>> 8);
byteBuf[2] = (byte)(v >>> 16);
byteBuf[3] = (byte)(v >>> 24);
byteBuf[4] = (byte)(v >>> 32);
byteBuf[5] = (byte)(v >>> 40);
byteBuf[6] = (byte)(v >>> 48);
byteBuf[7] = (byte)(v >>> 56);
ByteArrayLittleEndian.setLong(byteBuf, 0, v);
}
// REMIND: Once 6277756 is fixed, we should do a bulk write of all 8
// bytes here as we do in writeShort() and writeInt() for even better
@ -141,15 +122,15 @@ public abstract class ImageOutputStreamImpl
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len ; i++) {
int v = s.charAt(i);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
char v = s.charAt(i);
ByteArray.setChar(b, boff, v);
boff += 2;
}
} else {
for (int i = 0; i < len ; i++) {
int v = s.charAt(i);
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
char v = s.charAt(i);
ByteArrayLittleEndian.setChar(b, boff, v);
boff += 2;
}
}
@ -213,14 +194,14 @@ public abstract class ImageOutputStreamImpl
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
short v = s[off + i];
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
ByteArray.setShort(b, boff, v);
boff += 2;
}
} else {
for (int i = 0; i < len; i++) {
short v = s[off + i];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
ByteArrayLittleEndian.setShort(b, boff, v);
boff += 2;
}
}
@ -239,14 +220,14 @@ public abstract class ImageOutputStreamImpl
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
char v = c[off + i];
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
ByteArray.setChar(b, boff, v);
boff += 2;
}
} else {
for (int i = 0; i < len; i++) {
char v = c[off + i];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
ByteArrayLittleEndian.setChar(b, boff, v);
boff += 2;
}
}
@ -265,18 +246,14 @@ public abstract class ImageOutputStreamImpl
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int v = i[off + j];
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
ByteArray.setInt(b, boff, v);
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int v = i[off + j];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
ByteArrayLittleEndian.setInt(b, boff, v);
boff += 4;
}
}
@ -295,26 +272,14 @@ public abstract class ImageOutputStreamImpl
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
long v = l[off + i];
b[boff++] = (byte)(v >>> 56);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
ByteArray.setLong(b, boff, v);
boff += 8;
}
} else {
for (int i = 0; i < len; i++) {
long v = l[off + i];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 56);
ByteArrayLittleEndian.setLong(b, boff, v);
boff += 8;
}
}
@ -332,19 +297,15 @@ public abstract class ImageOutputStreamImpl
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
int v = Float.floatToIntBits(f[off + i]);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
float v = f[off + i];
ByteArray.setFloat(b, boff, v);
boff += 4;
}
} else {
for (int i = 0; i < len; i++) {
int v = Float.floatToIntBits(f[off + i]);
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
float v = f[off + i];
ByteArrayLittleEndian.setFloat(b, boff, v);
boff += 4;
}
}
@ -362,27 +323,15 @@ public abstract class ImageOutputStreamImpl
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
long v = Double.doubleToLongBits(d[off + i]);
b[boff++] = (byte)(v >>> 56);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
double v = d[off + i];
ByteArray.setDouble(b, boff, v);
boff += 8;
}
} else {
for (int i = 0; i < len; i++) {
long v = Double.doubleToLongBits(d[off + i]);
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 56);
double v = d[off + i];
ByteArrayLittleEndian.setDouble(b, boff, v);
boff += 8;
}
}

View File

@ -37,12 +37,9 @@ import javax.imageio.stream.MemoryCacheImageInputStream;
public class ReadFullyTest {
static final ByteOrder bigEndian = ByteOrder.BIG_ENDIAN;
static final ByteOrder littleEndian = ByteOrder.LITTLE_ENDIAN;
private static void expect(long e, long g) {
if (e != g) {
throw new RuntimeException("Expected " + e + ", got " + g);
private static void assertEquals(long actual, long expected) {
if (actual != expected) {
throw new AssertionError("Expected 0x" + Long.toHexString(expected) + ", got 0x" + Long.toHexString(actual));
}
}
@ -65,82 +62,82 @@ public class ReadFullyTest {
double[] d = new double[b.length/8];
iin.seek(0L);
iin.setByteOrder(bigEndian);
iin.setByteOrder(ByteOrder.BIG_ENDIAN);
iin.readFully(s, 0, s.length);
expect(s[0] & 0xffff, 0x1122);
expect(s[1] & 0xffff, 0x4499);
expect(s[2] & 0xffff, 0xAA33);
expect(s[3] & 0xffff, 0xBBCC);
assertEquals(s[0] & 0xffff, 0x1122);
assertEquals(s[1] & 0xffff, 0x4499);
assertEquals(s[2] & 0xffff, 0xAA33);
assertEquals(s[3] & 0xffff, 0xBBCC);
iin.seek(0L);
iin.setByteOrder(littleEndian);
iin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
iin.readFully(s, 0, s.length);
expect(s[0] & 0xffff, 0x2211);
expect(s[1] & 0xffff, 0x9944);
expect(s[2] & 0xffff, 0x33AA);
expect(s[3] & 0xffff, 0xCCBB);
assertEquals(s[0] & 0xffff, 0x2211);
assertEquals(s[1] & 0xffff, 0x9944);
assertEquals(s[2] & 0xffff, 0x33AA);
assertEquals(s[3] & 0xffff, 0xCCBB);
iin.seek(0L);
iin.setByteOrder(bigEndian);
iin.setByteOrder(ByteOrder.BIG_ENDIAN);
iin.readFully(c, 0, c.length);
expect(c[0], 0x1122);
expect(c[1], 0x4499);
expect(c[2], 0xAA33);
expect(c[3], 0xBBCC);
assertEquals(c[0], 0x1122);
assertEquals(c[1], 0x4499);
assertEquals(c[2], 0xAA33);
assertEquals(c[3], 0xBBCC);
iin.seek(0L);
iin.setByteOrder(littleEndian);
iin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
iin.readFully(c, 0, c.length);
expect(c[0], 0x2211);
expect(c[1], 0x9944);
expect(c[2], 0x33AA);
expect(c[3], 0xCCBB);
assertEquals(c[0], 0x2211);
assertEquals(c[1], 0x9944);
assertEquals(c[2], 0x33AA);
assertEquals(c[3], 0xCCBB);
iin.seek(0L);
iin.setByteOrder(bigEndian);
iin.setByteOrder(ByteOrder.BIG_ENDIAN);
iin.readFully(i, 0, i.length);
expect(i[0] & 0xffffffff, 0x11224499);
expect(i[1] & 0xffffffff, 0xAA33BBCC);
assertEquals(i[0] & 0xffffffff, 0x11224499);
assertEquals(i[1] & 0xffffffff, 0xAA33BBCC);
iin.seek(0L);
iin.setByteOrder(littleEndian);
iin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
iin.readFully(i, 0, i.length);
expect(i[0] & 0xffffffff, 0x99442211);
expect(i[1] & 0xffffffff, 0xCCBB33AA);
assertEquals(i[0] & 0xffffffff, 0x99442211);
assertEquals(i[1] & 0xffffffff, 0xCCBB33AA);
iin.seek(0L);
iin.setByteOrder(bigEndian);
iin.setByteOrder(ByteOrder.BIG_ENDIAN);
iin.readFully(f, 0, f.length);
expect(Float.floatToIntBits(f[0]) & 0xffffffff, 0x11224499);
expect(Float.floatToIntBits(f[1]) & 0xffffffff, 0xAA33BBCC);
assertEquals(Float.floatToIntBits(f[0]) & 0xffffffff, 0x11224499);
assertEquals(Float.floatToIntBits(f[1]) & 0xffffffff, 0xAA33BBCC);
iin.seek(0L);
iin.setByteOrder(littleEndian);
iin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
iin.readFully(f, 0, f.length);
expect(Float.floatToIntBits(f[0]) & 0xffffffff, 0x99442211);
expect(Float.floatToIntBits(f[1]) & 0xffffffff, 0xCCBB33AA);
assertEquals(Float.floatToIntBits(f[0]) & 0xffffffff, 0x99442211);
assertEquals(Float.floatToIntBits(f[1]) & 0xffffffff, 0xCCBB33AA);
iin.seek(0L);
iin.setByteOrder(bigEndian);
iin.setByteOrder(ByteOrder.BIG_ENDIAN);
iin.readFully(l, 0, l.length);
expect(l[0], 0x11224499AA33BBCCL);
assertEquals(l[0], 0x11224499AA33BBCCL);
iin.seek(0L);
iin.setByteOrder(littleEndian);
iin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
iin.readFully(l, 0, l.length);
expect(l[0], 0xCCBB33AA99442211L);
assertEquals(l[0], 0xCCBB33AA99442211L);
iin.seek(0L);
iin.setByteOrder(bigEndian);
iin.setByteOrder(ByteOrder.BIG_ENDIAN);
iin.readFully(d, 0, d.length);
expect(Double.doubleToLongBits(d[0]), 0x11224499AA33BBCCL);
assertEquals(Double.doubleToLongBits(d[0]), 0x11224499AA33BBCCL);
iin.seek(0L);
iin.setByteOrder(littleEndian);
iin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
iin.readFully(d, 0, d.length);
expect(Double.doubleToLongBits(d[0]), 0xCCBB33AA99442211L);
} catch (Exception ex) {
throw new RuntimeException("Got exception " + ex);
assertEquals(Double.doubleToLongBits(d[0]), 0xCCBB33AA99442211L);
} catch (Throwable ex) {
throw new RuntimeException("Got exception", ex);
}
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2022, 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.javax.imageio.stream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
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.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import javax.imageio.stream.ImageInputStreamImpl;
import javax.imageio.stream.ImageOutputStreamImpl;
/**
* Examine ImageInpuStream operations
*/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(3)
@State(Scope.Benchmark)
public class ImageInputStreamBench {
// private static final byte[] ARRAY = new byte[8];
private ImageInputStreamImpl imageInputStream;
@Setup
public void createInstants() {
// Various instants during the same day
imageInputStream = new ImageInputStreamImpl() {
@Override
public int read() {
throw new UnsupportedOperationException();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
//System.arraycopy(ARRAY, 0, b, off, len);
return len;
}
};
}
@Benchmark
public void readInt(Blackhole bh) throws IOException {
bh.consume(imageInputStream.readInt());
}
@Benchmark
public void readLong(Blackhole bh) throws IOException {
bh.consume(imageInputStream.readLong());
}
}