/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class VarHandleUnitTestHelpers {
public static boolean isRunningOnAndroid() {
return System.getProperty("java.vm.vendor").contains("Android");
}
public static boolean is64Bit() {
// The behaviour of certain accessors depends on the ISA word size.
if (isRunningOnAndroid()) {
try {
Class<?> runtimeClass = Class.forName("dalvik.system.VMRuntime");
MethodHandle getRuntimeMH =
MethodHandles.lookup()
.findStatic(
runtimeClass,
"getRuntime",
MethodType.methodType(runtimeClass));
Object runtime = getRuntimeMH.invoke();
MethodHandle is64BitMH =
MethodHandles.lookup()
.findVirtual(
runtimeClass,
"is64Bit",
MethodType.methodType(boolean.class));
return (boolean) is64BitMH.invoke(runtime);
} catch (Throwable t) {
throw new RuntimeException(t);
}
} else {
return System.getProperty("sun.arch.data.model").equals("64");
}
}
public static boolean getBytesAs_boolean(byte[] array, int index, ByteOrder order) {
return getBytesAs_boolean(ByteBuffer.wrap(array), index, order);
}
public static byte getBytesAs_byte(byte[] array, int index, ByteOrder order) {
return getBytesAs_byte(ByteBuffer.wrap(array), index, order);
}
public static char getBytesAs_char(byte[] array, int index, ByteOrder order) {
return getBytesAs_char(ByteBuffer.wrap(array), index, order);
}
public static short getBytesAs_short(byte[] array, int index, ByteOrder order) {
return getBytesAs_short(ByteBuffer.wrap(array), index, order);
}
public static int getBytesAs_int(byte[] array, int index, ByteOrder order) {
return getBytesAs_int(ByteBuffer.wrap(array), index, order);
}
public static long getBytesAs_long(byte[] array, int index, ByteOrder order) {
return getBytesAs_long(ByteBuffer.wrap(array), index, order);
}
public static float getBytesAs_float(byte[] array, int index, ByteOrder order) {
return getBytesAs_float(ByteBuffer.wrap(array), index, order);
}
public static double getBytesAs_double(byte[] array, int index, ByteOrder order) {
return getBytesAs_double(ByteBuffer.wrap(array), index, order);
}
public static boolean getBytesAs_boolean(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).get(index) != 0;
}
public static byte getBytesAs_byte(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).get(index);
}
public static char getBytesAs_char(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).getChar(index);
}
public static short getBytesAs_short(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).getShort(index);
}
public static int getBytesAs_int(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).getInt(index);
}
public static long getBytesAs_long(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).getLong(index);
}
public static float getBytesAs_float(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).getFloat(index);
}
public static double getBytesAs_double(ByteBuffer buffer, int index, ByteOrder order) {
return buffer.order(order).getDouble(index);
}
public static void setBytesAs_boolean(byte[] array, int index, boolean value, ByteOrder order) {
setBytesAs_boolean(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_byte(byte[] array, int index, byte value, ByteOrder order) {
setBytesAs_byte(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_char(byte[] array, int index, char value, ByteOrder order) {
setBytesAs_char(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_short(byte[] array, int index, short value, ByteOrder order) {
setBytesAs_short(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_int(byte[] array, int index, int value, ByteOrder order) {
setBytesAs_int(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_long(byte[] array, int index, long value, ByteOrder order) {
setBytesAs_long(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_float(byte[] array, int index, float value, ByteOrder order) {
setBytesAs_float(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_double(byte[] array, int index, double value, ByteOrder order) {
setBytesAs_double(ByteBuffer.wrap(array), index, value, order);
}
public static void setBytesAs_boolean(
ByteBuffer buffer, int index, boolean value, ByteOrder order) {
buffer.order(order).put(index, value ? (byte) 1 : (byte) 0);
}
public static void setBytesAs_byte(ByteBuffer buffer, int index, byte value, ByteOrder order) {
buffer.order(order).put(index, value);
}
public static void setBytesAs_char(ByteBuffer buffer, int index, char value, ByteOrder order) {
buffer.order(order).putChar(index, value);
}
public static void setBytesAs_short(
ByteBuffer buffer, int index, short value, ByteOrder order) {
buffer.order(order).putShort(index, value);
}
public static void setBytesAs_int(ByteBuffer buffer, int index, int value, ByteOrder order) {
buffer.order(order).putInt(index, value);
}
public static void setBytesAs_long(ByteBuffer buffer, int index, long value, ByteOrder order) {
buffer.order(order).putLong(index, value);
}
public static void setBytesAs_float(
ByteBuffer buffer, int index, float value, ByteOrder order) {
buffer.order(order).putFloat(index, value);
}
public static void setBytesAs_double(
ByteBuffer buffer, int index, double value, ByteOrder order) {
buffer.order(order).putDouble(index, value);
}
// Until ART is running on an OpenJDK9 based runtime, there are no
// calls to help with alignment. OpenJDK9 introduces
// ByteBuffer.alignedSlice() and ByteBuffer.alignmentOffset(). RI
// and ART have different data structure alignments which may make
// porting code interesting.
public static int alignedOffset_char(ByteBuffer buffer, int start) {
return alignedOffset_short(buffer, start);
}
public static int alignedOffset_short(ByteBuffer buffer, int start) {
for (int i = 0; i < Short.SIZE; ++i) {
try {
vh_probe_short.getVolatile(buffer, start + i);
return start + i;
} catch (IllegalStateException e) {
// Unaligned access.
}
}
return start;
}
public static int alignedOffset_int(ByteBuffer buffer, int start) {
for (int i = 0; i < Integer.SIZE; ++i) {
try {
vh_probe_int.getVolatile(buffer, start + i);
return start + i;
} catch (IllegalStateException e) {
// Unaligned access.
} catch (Exception e) {
break;
}
}
return start;
}
public static int alignedOffset_long(ByteBuffer buffer, int start) {
for (int i = 0; i < Long.SIZE; ++i) {
try {
vh_probe_long.getVolatile(buffer, start + i);
return start + i;
} catch (IllegalStateException e) {
// Unaligned access.
} catch (UnsupportedOperationException e) {
// 64-bit operation is not supported irrespective of alignment.
break;
}
}
return start;
}
public static int alignedOffset_float(ByteBuffer buffer, int start) {
return alignedOffset_int(buffer, start);
}
public static int alignedOffset_double(ByteBuffer buffer, int start) {
return alignedOffset_long(buffer, start);
}
public static int alignedOffset_char(byte[] array, int start) {
return alignedOffset_char(ByteBuffer.wrap(array), start);
}
public static int alignedOffset_short(byte[] array, int start) {
return alignedOffset_short(ByteBuffer.wrap(array), start);
}
public static int alignedOffset_int(byte[] array, int start) {
return alignedOffset_int(ByteBuffer.wrap(array), start);
}
public static int alignedOffset_long(byte[] array, int start) {
return alignedOffset_long(ByteBuffer.wrap(array), start);
}
public static int alignedOffset_float(byte[] array, int start) {
return alignedOffset_float(ByteBuffer.wrap(array), start);
}
public static int alignedOffset_double(byte[] array, int start) {
return alignedOffset_double(ByteBuffer.wrap(array), start);
}
static {
ByteOrder order = ByteOrder.LITTLE_ENDIAN;
vh_probe_short = MethodHandles.byteBufferViewVarHandle(short[].class, order);
vh_probe_int = MethodHandles.byteBufferViewVarHandle(int[].class, order);
vh_probe_long = MethodHandles.byteBufferViewVarHandle(long[].class, order);
}
private static final VarHandle vh_probe_short;
private static final VarHandle vh_probe_int;
private static final VarHandle vh_probe_long;
}