1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.invoke.MethodHandle; 18 import java.lang.invoke.MethodHandles; 19 import java.lang.invoke.MethodType; 20 import java.lang.invoke.VarHandle; 21 import java.nio.ByteBuffer; 22 import java.nio.ByteOrder; 23 24 public class VarHandleUnitTestHelpers { isRunningOnAndroid()25 public static boolean isRunningOnAndroid() { 26 return System.getProperty("java.vm.vendor").contains("Android"); 27 } 28 is64Bit()29 public static boolean is64Bit() { 30 // The behaviour of certain accessors depends on the ISA word size. 31 if (isRunningOnAndroid()) { 32 try { 33 Class<?> runtimeClass = Class.forName("dalvik.system.VMRuntime"); 34 MethodHandle getRuntimeMH = 35 MethodHandles.lookup() 36 .findStatic( 37 runtimeClass, 38 "getRuntime", 39 MethodType.methodType(runtimeClass)); 40 Object runtime = getRuntimeMH.invoke(); 41 MethodHandle is64BitMH = 42 MethodHandles.lookup() 43 .findVirtual( 44 runtimeClass, 45 "is64Bit", 46 MethodType.methodType(boolean.class)); 47 return (boolean) is64BitMH.invoke(runtime); 48 } catch (Throwable t) { 49 throw new RuntimeException(t); 50 } 51 } else { 52 return System.getProperty("sun.arch.data.model").equals("64"); 53 } 54 } 55 getBytesAs_boolean(byte[] array, int index, ByteOrder order)56 public static boolean getBytesAs_boolean(byte[] array, int index, ByteOrder order) { 57 return getBytesAs_boolean(ByteBuffer.wrap(array), index, order); 58 } 59 getBytesAs_byte(byte[] array, int index, ByteOrder order)60 public static byte getBytesAs_byte(byte[] array, int index, ByteOrder order) { 61 return getBytesAs_byte(ByteBuffer.wrap(array), index, order); 62 } 63 getBytesAs_char(byte[] array, int index, ByteOrder order)64 public static char getBytesAs_char(byte[] array, int index, ByteOrder order) { 65 return getBytesAs_char(ByteBuffer.wrap(array), index, order); 66 } 67 getBytesAs_short(byte[] array, int index, ByteOrder order)68 public static short getBytesAs_short(byte[] array, int index, ByteOrder order) { 69 return getBytesAs_short(ByteBuffer.wrap(array), index, order); 70 } 71 getBytesAs_int(byte[] array, int index, ByteOrder order)72 public static int getBytesAs_int(byte[] array, int index, ByteOrder order) { 73 return getBytesAs_int(ByteBuffer.wrap(array), index, order); 74 } 75 getBytesAs_long(byte[] array, int index, ByteOrder order)76 public static long getBytesAs_long(byte[] array, int index, ByteOrder order) { 77 return getBytesAs_long(ByteBuffer.wrap(array), index, order); 78 } 79 getBytesAs_float(byte[] array, int index, ByteOrder order)80 public static float getBytesAs_float(byte[] array, int index, ByteOrder order) { 81 return getBytesAs_float(ByteBuffer.wrap(array), index, order); 82 } 83 getBytesAs_double(byte[] array, int index, ByteOrder order)84 public static double getBytesAs_double(byte[] array, int index, ByteOrder order) { 85 return getBytesAs_double(ByteBuffer.wrap(array), index, order); 86 } 87 getBytesAs_boolean(ByteBuffer buffer, int index, ByteOrder order)88 public static boolean getBytesAs_boolean(ByteBuffer buffer, int index, ByteOrder order) { 89 return buffer.order(order).get(index) != 0; 90 } 91 getBytesAs_byte(ByteBuffer buffer, int index, ByteOrder order)92 public static byte getBytesAs_byte(ByteBuffer buffer, int index, ByteOrder order) { 93 return buffer.order(order).get(index); 94 } 95 getBytesAs_char(ByteBuffer buffer, int index, ByteOrder order)96 public static char getBytesAs_char(ByteBuffer buffer, int index, ByteOrder order) { 97 return buffer.order(order).getChar(index); 98 } 99 getBytesAs_short(ByteBuffer buffer, int index, ByteOrder order)100 public static short getBytesAs_short(ByteBuffer buffer, int index, ByteOrder order) { 101 return buffer.order(order).getShort(index); 102 } 103 getBytesAs_int(ByteBuffer buffer, int index, ByteOrder order)104 public static int getBytesAs_int(ByteBuffer buffer, int index, ByteOrder order) { 105 return buffer.order(order).getInt(index); 106 } 107 getBytesAs_long(ByteBuffer buffer, int index, ByteOrder order)108 public static long getBytesAs_long(ByteBuffer buffer, int index, ByteOrder order) { 109 return buffer.order(order).getLong(index); 110 } 111 getBytesAs_float(ByteBuffer buffer, int index, ByteOrder order)112 public static float getBytesAs_float(ByteBuffer buffer, int index, ByteOrder order) { 113 return buffer.order(order).getFloat(index); 114 } 115 getBytesAs_double(ByteBuffer buffer, int index, ByteOrder order)116 public static double getBytesAs_double(ByteBuffer buffer, int index, ByteOrder order) { 117 return buffer.order(order).getDouble(index); 118 } 119 setBytesAs_boolean(byte[] array, int index, boolean value, ByteOrder order)120 public static void setBytesAs_boolean(byte[] array, int index, boolean value, ByteOrder order) { 121 setBytesAs_boolean(ByteBuffer.wrap(array), index, value, order); 122 } 123 setBytesAs_byte(byte[] array, int index, byte value, ByteOrder order)124 public static void setBytesAs_byte(byte[] array, int index, byte value, ByteOrder order) { 125 setBytesAs_byte(ByteBuffer.wrap(array), index, value, order); 126 } 127 setBytesAs_char(byte[] array, int index, char value, ByteOrder order)128 public static void setBytesAs_char(byte[] array, int index, char value, ByteOrder order) { 129 setBytesAs_char(ByteBuffer.wrap(array), index, value, order); 130 } 131 setBytesAs_short(byte[] array, int index, short value, ByteOrder order)132 public static void setBytesAs_short(byte[] array, int index, short value, ByteOrder order) { 133 setBytesAs_short(ByteBuffer.wrap(array), index, value, order); 134 } 135 setBytesAs_int(byte[] array, int index, int value, ByteOrder order)136 public static void setBytesAs_int(byte[] array, int index, int value, ByteOrder order) { 137 setBytesAs_int(ByteBuffer.wrap(array), index, value, order); 138 } 139 setBytesAs_long(byte[] array, int index, long value, ByteOrder order)140 public static void setBytesAs_long(byte[] array, int index, long value, ByteOrder order) { 141 setBytesAs_long(ByteBuffer.wrap(array), index, value, order); 142 } 143 setBytesAs_float(byte[] array, int index, float value, ByteOrder order)144 public static void setBytesAs_float(byte[] array, int index, float value, ByteOrder order) { 145 setBytesAs_float(ByteBuffer.wrap(array), index, value, order); 146 } 147 setBytesAs_double(byte[] array, int index, double value, ByteOrder order)148 public static void setBytesAs_double(byte[] array, int index, double value, ByteOrder order) { 149 setBytesAs_double(ByteBuffer.wrap(array), index, value, order); 150 } 151 setBytesAs_boolean( ByteBuffer buffer, int index, boolean value, ByteOrder order)152 public static void setBytesAs_boolean( 153 ByteBuffer buffer, int index, boolean value, ByteOrder order) { 154 buffer.order(order).put(index, value ? (byte) 1 : (byte) 0); 155 } 156 setBytesAs_byte(ByteBuffer buffer, int index, byte value, ByteOrder order)157 public static void setBytesAs_byte(ByteBuffer buffer, int index, byte value, ByteOrder order) { 158 buffer.order(order).put(index, value); 159 } 160 setBytesAs_char(ByteBuffer buffer, int index, char value, ByteOrder order)161 public static void setBytesAs_char(ByteBuffer buffer, int index, char value, ByteOrder order) { 162 buffer.order(order).putChar(index, value); 163 } 164 setBytesAs_short( ByteBuffer buffer, int index, short value, ByteOrder order)165 public static void setBytesAs_short( 166 ByteBuffer buffer, int index, short value, ByteOrder order) { 167 buffer.order(order).putShort(index, value); 168 } 169 setBytesAs_int(ByteBuffer buffer, int index, int value, ByteOrder order)170 public static void setBytesAs_int(ByteBuffer buffer, int index, int value, ByteOrder order) { 171 buffer.order(order).putInt(index, value); 172 } 173 setBytesAs_long(ByteBuffer buffer, int index, long value, ByteOrder order)174 public static void setBytesAs_long(ByteBuffer buffer, int index, long value, ByteOrder order) { 175 buffer.order(order).putLong(index, value); 176 } 177 setBytesAs_float( ByteBuffer buffer, int index, float value, ByteOrder order)178 public static void setBytesAs_float( 179 ByteBuffer buffer, int index, float value, ByteOrder order) { 180 buffer.order(order).putFloat(index, value); 181 } 182 setBytesAs_double( ByteBuffer buffer, int index, double value, ByteOrder order)183 public static void setBytesAs_double( 184 ByteBuffer buffer, int index, double value, ByteOrder order) { 185 buffer.order(order).putDouble(index, value); 186 } 187 188 // Until ART is running on an OpenJDK9 based runtime, there are no 189 // calls to help with alignment. OpenJDK9 introduces 190 // ByteBuffer.alignedSlice() and ByteBuffer.alignmentOffset(). RI 191 // and ART have different data structure alignments which may make 192 // porting code interesting. 193 alignedOffset_char(ByteBuffer buffer, int start)194 public static int alignedOffset_char(ByteBuffer buffer, int start) { 195 return alignedOffset_short(buffer, start); 196 } 197 alignedOffset_short(ByteBuffer buffer, int start)198 public static int alignedOffset_short(ByteBuffer buffer, int start) { 199 for (int i = 0; i < Short.SIZE; ++i) { 200 try { 201 vh_probe_short.getVolatile(buffer, start + i); 202 return start + i; 203 } catch (IllegalStateException e) { 204 // Unaligned access. 205 } 206 } 207 return start; 208 } 209 alignedOffset_int(ByteBuffer buffer, int start)210 public static int alignedOffset_int(ByteBuffer buffer, int start) { 211 for (int i = 0; i < Integer.SIZE; ++i) { 212 try { 213 vh_probe_int.getVolatile(buffer, start + i); 214 return start + i; 215 } catch (IllegalStateException e) { 216 // Unaligned access. 217 } catch (Exception e) { 218 break; 219 } 220 } 221 return start; 222 } 223 alignedOffset_long(ByteBuffer buffer, int start)224 public static int alignedOffset_long(ByteBuffer buffer, int start) { 225 for (int i = 0; i < Long.SIZE; ++i) { 226 try { 227 vh_probe_long.getVolatile(buffer, start + i); 228 return start + i; 229 } catch (IllegalStateException e) { 230 // Unaligned access. 231 } catch (UnsupportedOperationException e) { 232 // 64-bit operation is not supported irrespective of alignment. 233 break; 234 } 235 } 236 return start; 237 } 238 alignedOffset_float(ByteBuffer buffer, int start)239 public static int alignedOffset_float(ByteBuffer buffer, int start) { 240 return alignedOffset_int(buffer, start); 241 } 242 alignedOffset_double(ByteBuffer buffer, int start)243 public static int alignedOffset_double(ByteBuffer buffer, int start) { 244 return alignedOffset_long(buffer, start); 245 } 246 alignedOffset_char(byte[] array, int start)247 public static int alignedOffset_char(byte[] array, int start) { 248 return alignedOffset_char(ByteBuffer.wrap(array), start); 249 } 250 alignedOffset_short(byte[] array, int start)251 public static int alignedOffset_short(byte[] array, int start) { 252 return alignedOffset_short(ByteBuffer.wrap(array), start); 253 } 254 alignedOffset_int(byte[] array, int start)255 public static int alignedOffset_int(byte[] array, int start) { 256 return alignedOffset_int(ByteBuffer.wrap(array), start); 257 } 258 alignedOffset_long(byte[] array, int start)259 public static int alignedOffset_long(byte[] array, int start) { 260 return alignedOffset_long(ByteBuffer.wrap(array), start); 261 } 262 alignedOffset_float(byte[] array, int start)263 public static int alignedOffset_float(byte[] array, int start) { 264 return alignedOffset_float(ByteBuffer.wrap(array), start); 265 } 266 alignedOffset_double(byte[] array, int start)267 public static int alignedOffset_double(byte[] array, int start) { 268 return alignedOffset_double(ByteBuffer.wrap(array), start); 269 } 270 271 static { 272 ByteOrder order = ByteOrder.LITTLE_ENDIAN; 273 vh_probe_short = MethodHandles.byteBufferViewVarHandle(short[].class, order); 274 vh_probe_int = MethodHandles.byteBufferViewVarHandle(int[].class, order); 275 vh_probe_long = MethodHandles.byteBufferViewVarHandle(long[].class, order); 276 } 277 278 private static final VarHandle vh_probe_short; 279 private static final VarHandle vh_probe_int; 280 private static final VarHandle vh_probe_long; 281 } 282