/* * 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; }