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