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;