mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8300235: Use VarHandle access in Image(Input | Output)StreamImpl classes
Reviewed-by: rriggs
This commit is contained in:
parent
406021ad58
commit
b504c9411e
6 changed files with 624 additions and 249 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue