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 
createFilledByteArray(int size)56     public static byte[] createFilledByteArray(int size) {
57         byte[] array = new byte[size];
58         for (int i = 0; i != size; ++i) {
59             array[i] = (byte) (i * 47 + 11);
60         }
61         return array;
62     }
63 
getBytesAs_boolean(byte[] array, int index, ByteOrder order)64     public static boolean getBytesAs_boolean(byte[] array, int index, ByteOrder order) {
65         return getBytesAs_boolean(ByteBuffer.wrap(array), index, order);
66     }
67 
getBytesAs_byte(byte[] array, int index, ByteOrder order)68     public static byte getBytesAs_byte(byte[] array, int index, ByteOrder order) {
69         return getBytesAs_byte(ByteBuffer.wrap(array), index, order);
70     }
71 
getBytesAs_char(byte[] array, int index, ByteOrder order)72     public static char getBytesAs_char(byte[] array, int index, ByteOrder order) {
73         return getBytesAs_char(ByteBuffer.wrap(array), index, order);
74     }
75 
getBytesAs_short(byte[] array, int index, ByteOrder order)76     public static short getBytesAs_short(byte[] array, int index, ByteOrder order) {
77         return getBytesAs_short(ByteBuffer.wrap(array), index, order);
78     }
79 
getBytesAs_int(byte[] array, int index, ByteOrder order)80     public static int getBytesAs_int(byte[] array, int index, ByteOrder order) {
81         return getBytesAs_int(ByteBuffer.wrap(array), index, order);
82     }
83 
getBytesAs_long(byte[] array, int index, ByteOrder order)84     public static long getBytesAs_long(byte[] array, int index, ByteOrder order) {
85         return getBytesAs_long(ByteBuffer.wrap(array), index, order);
86     }
87 
getBytesAs_float(byte[] array, int index, ByteOrder order)88     public static float getBytesAs_float(byte[] array, int index, ByteOrder order) {
89         return getBytesAs_float(ByteBuffer.wrap(array), index, order);
90     }
91 
getBytesAs_double(byte[] array, int index, ByteOrder order)92     public static double getBytesAs_double(byte[] array, int index, ByteOrder order) {
93         return getBytesAs_double(ByteBuffer.wrap(array), index, order);
94     }
95 
getBytesAs_boolean(ByteBuffer buffer, int index, ByteOrder order)96     public static boolean getBytesAs_boolean(ByteBuffer buffer, int index, ByteOrder order) {
97         return buffer.order(order).get(index) != 0;
98     }
99 
getBytesAs_byte(ByteBuffer buffer, int index, ByteOrder order)100     public static byte getBytesAs_byte(ByteBuffer buffer, int index, ByteOrder order) {
101         return buffer.order(order).get(index);
102     }
103 
getBytesAs_char(ByteBuffer buffer, int index, ByteOrder order)104     public static char getBytesAs_char(ByteBuffer buffer, int index, ByteOrder order) {
105         return buffer.order(order).getChar(index);
106     }
107 
getBytesAs_short(ByteBuffer buffer, int index, ByteOrder order)108     public static short getBytesAs_short(ByteBuffer buffer, int index, ByteOrder order) {
109         return buffer.order(order).getShort(index);
110     }
111 
getBytesAs_int(ByteBuffer buffer, int index, ByteOrder order)112     public static int getBytesAs_int(ByteBuffer buffer, int index, ByteOrder order) {
113         return buffer.order(order).getInt(index);
114     }
115 
getBytesAs_long(ByteBuffer buffer, int index, ByteOrder order)116     public static long getBytesAs_long(ByteBuffer buffer, int index, ByteOrder order) {
117         return buffer.order(order).getLong(index);
118     }
119 
getBytesAs_float(ByteBuffer buffer, int index, ByteOrder order)120     public static float getBytesAs_float(ByteBuffer buffer, int index, ByteOrder order) {
121         return buffer.order(order).getFloat(index);
122     }
123 
getBytesAs_double(ByteBuffer buffer, int index, ByteOrder order)124     public static double getBytesAs_double(ByteBuffer buffer, int index, ByteOrder order) {
125         return buffer.order(order).getDouble(index);
126     }
127 
setBytesAs_boolean(byte[] array, int index, boolean value, ByteOrder order)128     public static void setBytesAs_boolean(byte[] array, int index, boolean value, ByteOrder order) {
129         setBytesAs_boolean(ByteBuffer.wrap(array), index, value, order);
130     }
131 
setBytesAs_byte(byte[] array, int index, byte value, ByteOrder order)132     public static void setBytesAs_byte(byte[] array, int index, byte value, ByteOrder order) {
133         setBytesAs_byte(ByteBuffer.wrap(array), index, value, order);
134     }
135 
setBytesAs_char(byte[] array, int index, char value, ByteOrder order)136     public static void setBytesAs_char(byte[] array, int index, char value, ByteOrder order) {
137         setBytesAs_char(ByteBuffer.wrap(array), index, value, order);
138     }
139 
setBytesAs_short(byte[] array, int index, short value, ByteOrder order)140     public static void setBytesAs_short(byte[] array, int index, short value, ByteOrder order) {
141         setBytesAs_short(ByteBuffer.wrap(array), index, value, order);
142     }
143 
setBytesAs_int(byte[] array, int index, int value, ByteOrder order)144     public static void setBytesAs_int(byte[] array, int index, int value, ByteOrder order) {
145         setBytesAs_int(ByteBuffer.wrap(array), index, value, order);
146     }
147 
setBytesAs_long(byte[] array, int index, long value, ByteOrder order)148     public static void setBytesAs_long(byte[] array, int index, long value, ByteOrder order) {
149         setBytesAs_long(ByteBuffer.wrap(array), index, value, order);
150     }
151 
setBytesAs_float(byte[] array, int index, float value, ByteOrder order)152     public static void setBytesAs_float(byte[] array, int index, float value, ByteOrder order) {
153         setBytesAs_float(ByteBuffer.wrap(array), index, value, order);
154     }
155 
setBytesAs_double(byte[] array, int index, double value, ByteOrder order)156     public static void setBytesAs_double(byte[] array, int index, double value, ByteOrder order) {
157         setBytesAs_double(ByteBuffer.wrap(array), index, value, order);
158     }
159 
setBytesAs_boolean( ByteBuffer buffer, int index, boolean value, ByteOrder order)160     public static void setBytesAs_boolean(
161             ByteBuffer buffer, int index, boolean value, ByteOrder order) {
162         buffer.order(order).put(index, value ? (byte) 1 : (byte) 0);
163     }
164 
setBytesAs_byte(ByteBuffer buffer, int index, byte value, ByteOrder order)165     public static void setBytesAs_byte(ByteBuffer buffer, int index, byte value, ByteOrder order) {
166         buffer.order(order).put(index, value);
167     }
168 
setBytesAs_char(ByteBuffer buffer, int index, char value, ByteOrder order)169     public static void setBytesAs_char(ByteBuffer buffer, int index, char value, ByteOrder order) {
170         buffer.order(order).putChar(index, value);
171     }
172 
setBytesAs_short( ByteBuffer buffer, int index, short value, ByteOrder order)173     public static void setBytesAs_short(
174             ByteBuffer buffer, int index, short value, ByteOrder order) {
175         buffer.order(order).putShort(index, value);
176     }
177 
setBytesAs_int(ByteBuffer buffer, int index, int value, ByteOrder order)178     public static void setBytesAs_int(ByteBuffer buffer, int index, int value, ByteOrder order) {
179         buffer.order(order).putInt(index, value);
180     }
181 
setBytesAs_long(ByteBuffer buffer, int index, long value, ByteOrder order)182     public static void setBytesAs_long(ByteBuffer buffer, int index, long value, ByteOrder order) {
183         buffer.order(order).putLong(index, value);
184     }
185 
setBytesAs_float( ByteBuffer buffer, int index, float value, ByteOrder order)186     public static void setBytesAs_float(
187             ByteBuffer buffer, int index, float value, ByteOrder order) {
188         buffer.order(order).putFloat(index, value);
189     }
190 
setBytesAs_double( ByteBuffer buffer, int index, double value, ByteOrder order)191     public static void setBytesAs_double(
192             ByteBuffer buffer, int index, double value, ByteOrder order) {
193         buffer.order(order).putDouble(index, value);
194     }
195 
196     // Until ART is running on an OpenJDK9 based runtime, there are no
197     // calls to help with alignment. OpenJDK9 introduces
198     // ByteBuffer.alignedSlice() and ByteBuffer.alignmentOffset(). RI
199     // and ART have different data structure alignments which may make
200     // porting code interesting.
201 
alignedOffset_char(ByteBuffer buffer, int start)202     public static int alignedOffset_char(ByteBuffer buffer, int start) {
203         return alignedOffset_short(buffer, start);
204     }
205 
alignedOffset_short(ByteBuffer buffer, int start)206     public static int alignedOffset_short(ByteBuffer buffer, int start) {
207         for (int i = 0; i < Short.SIZE; ++i) {
208             try {
209                 vh_probe_short.getVolatile(buffer, start + i);
210                 return start + i;
211             } catch (IllegalStateException e) {
212                 // Unaligned access.
213             }
214         }
215         return start;
216     }
217 
alignedOffset_int(ByteBuffer buffer, int start)218     public static int alignedOffset_int(ByteBuffer buffer, int start) {
219         for (int i = 0; i < Integer.SIZE; ++i) {
220             try {
221                 vh_probe_int.getVolatile(buffer, start + i);
222                 return start + i;
223             } catch (IllegalStateException e) {
224                 // Unaligned access.
225             } catch (Exception e) {
226                 break;
227             }
228         }
229         return start;
230     }
231 
alignedOffset_long(ByteBuffer buffer, int start)232     public static int alignedOffset_long(ByteBuffer buffer, int start) {
233         for (int i = 0; i < Long.SIZE; ++i) {
234             try {
235                 vh_probe_long.getVolatile(buffer, start + i);
236                 return start + i;
237             } catch (IllegalStateException e) {
238                 // Unaligned access.
239             } catch (UnsupportedOperationException e) {
240                 // 64-bit operation is not supported irrespective of alignment.
241                 break;
242             }
243         }
244         return start;
245     }
246 
alignedOffset_float(ByteBuffer buffer, int start)247     public static int alignedOffset_float(ByteBuffer buffer, int start) {
248         return alignedOffset_int(buffer, start);
249     }
250 
alignedOffset_double(ByteBuffer buffer, int start)251     public static int alignedOffset_double(ByteBuffer buffer, int start) {
252         return alignedOffset_long(buffer, start);
253     }
254 
alignedOffset_char(byte[] array, int start)255     public static int alignedOffset_char(byte[] array, int start) {
256         return alignedOffset_char(ByteBuffer.wrap(array), start);
257     }
258 
alignedOffset_short(byte[] array, int start)259     public static int alignedOffset_short(byte[] array, int start) {
260         return alignedOffset_short(ByteBuffer.wrap(array), start);
261     }
262 
alignedOffset_int(byte[] array, int start)263     public static int alignedOffset_int(byte[] array, int start) {
264         return alignedOffset_int(ByteBuffer.wrap(array), start);
265     }
266 
alignedOffset_long(byte[] array, int start)267     public static int alignedOffset_long(byte[] array, int start) {
268         return alignedOffset_long(ByteBuffer.wrap(array), start);
269     }
270 
alignedOffset_float(byte[] array, int start)271     public static int alignedOffset_float(byte[] array, int start) {
272         return alignedOffset_float(ByteBuffer.wrap(array), start);
273     }
274 
alignedOffset_double(byte[] array, int start)275     public static int alignedOffset_double(byte[] array, int start) {
276         return alignedOffset_double(ByteBuffer.wrap(array), start);
277     }
278 
279     static {
280         ByteOrder order = ByteOrder.LITTLE_ENDIAN;
281         vh_probe_short = MethodHandles.byteBufferViewVarHandle(short[].class, order);
282         vh_probe_int = MethodHandles.byteBufferViewVarHandle(int[].class, order);
283         vh_probe_long = MethodHandles.byteBufferViewVarHandle(long[].class, order);
284     }
285 
286     private static final VarHandle vh_probe_short;
287     private static final VarHandle vh_probe_int;
288     private static final VarHandle vh_probe_long;
289 }
290