1/*
2 * Copyright (C) 2016 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
17import java.lang.invoke.MethodHandle;
18import java.lang.invoke.MethodHandles;
19import java.lang.invoke.MethodHandles.Lookup;
20import java.lang.invoke.MethodType;
21import java.lang.invoke.WrongMethodTypeException;
22import java.lang.reflect.Constructor;
23import java.lang.reflect.Field;
24import java.lang.reflect.Method;
25import java.nio.charset.Charset;
26import java.nio.charset.StandardCharsets;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.List;
30
31public class Main {
32  public static void assertTrue(boolean value) {
33    if (!value) {
34      throw new AssertionError("assertTrue value: " + value);
35    }
36  }
37
38  public static void assertFalse(boolean value) {
39    if (value) {
40      throw new AssertionError("assertTrue value: " + value);
41    }
42  }
43
44  public static void assertEquals(int i1, int i2) {
45    if (i1 == i2) { return; }
46    throw new AssertionError("assertEquals i1: " + i1 + ", i2: " + i2);
47  }
48
49  public static void assertEquals(long i1, long i2) {
50    if (i1 == i2) { return; }
51    throw new AssertionError("assertEquals l1: " + i1 + ", l2: " + i2);
52  }
53
54  public static void assertEquals(Object o, Object p) {
55    if (o == p) { return; }
56    if (o != null && p != null && o.equals(p)) { return; }
57    throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p);
58  }
59
60  public static void assertEquals(String s1, String s2) {
61    if (s1 == s2) {
62      return;
63    }
64
65    if (s1 != null && s2 != null && s1.equals(s2)) {
66      return;
67    }
68
69    throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
70  }
71
72  public static void fail() {
73    System.out.println("fail");
74    Thread.dumpStack();
75  }
76
77  public static void fail(String message) {
78    System.out.println("fail: " + message);
79    Thread.dumpStack();
80  }
81
82  public static int Min2Print2(int a, int b) {
83    int[] values = new int[] { a, b };
84    System.out.println("Running Main.Min2Print2(" + Arrays.toString(values) + ")");
85    return a > b ? a : b;
86  }
87
88  public static int Min2Print3(int a, int b, int c) {
89    int[] values = new int[] { a, b, c };
90    System.out.println("Running Main.Min2Print3(" + Arrays.toString(values) + ")");
91    return a > b ? a : b;
92  }
93
94  public static int Min2Print6(int a, int b, int c, int d, int e, int f) {
95    int[] values = new int[] { a, b, c, d, e, f };
96    System.out.println("Running Main.Min2Print6(" + Arrays.toString(values) + ")");
97    return a > b ? a : b;
98  }
99
100  public static int Min2Print26(int a, int b, int c, int d,
101                                int e, int f, int g, int h,
102                                int i, int j, int k, int l,
103                                int m, int n, int o, int p,
104                                int q, int r, int s, int t,
105                                int u, int v, int w, int x,
106                                int y, int z) {
107    int[] values = new int[] { a, b, c, d, e, f, g, h, i, j, k, l, m,
108                               n, o, p, q, r, s, t, u, v, w, x, y, z };
109    System.out.println("Running Main.Min2Print26(" + Arrays.toString(values) + ")");
110    return a > b ? a : b;
111  }
112
113  public static void $opt$BasicTest() throws Throwable {
114    MethodHandle mh;
115    mh = MethodHandles.lookup().findStatic(
116        Main.class, "Min2Print2", MethodType.methodType(int.class, int.class, int.class));
117    assertEquals((int) mh.invokeExact(33, -4), 33);
118    assertEquals((int) mh.invokeExact(-4, 33), 33);
119
120    mh = MethodHandles.lookup().findStatic(
121        Main.class, "Min2Print3",
122        MethodType.methodType(int.class, int.class, int.class, int.class));
123    assertEquals((int) mh.invokeExact(33, -4, 17), 33);
124    assertEquals((int) mh.invokeExact(-4, 17, 33), 17);
125    assertEquals((int) mh.invokeExact(17, 33, -4), 33);
126
127    mh = MethodHandles.lookup().findStatic(
128        Main.class, "Min2Print6",
129        MethodType.methodType(
130            int.class, int.class, int.class, int.class, int.class, int.class, int.class));
131    assertEquals((int) mh.invokeExact(33, -4, 77, 88, 99, 111), 33);
132    try {
133        // Too few arguments
134        assertEquals((int) mh.invokeExact(33, -4, 77, 88), 33);
135        fail("No WMTE for too few arguments");
136    } catch (WrongMethodTypeException e) {}
137    try {
138        // Too many arguments
139        assertEquals((int) mh.invokeExact(33, -4, 77, 88, 89, 90, 91), 33);
140        fail("No WMTE for too many arguments");
141    } catch (WrongMethodTypeException e) {}
142    assertEquals((int) mh.invokeExact(-4, 77, 88, 99, 111, 33), 77);
143    assertEquals((int) mh.invokeExact(77, 88, 99, 111, 33, -4), 88);
144    assertEquals((int) mh.invokeExact(88, 99, 111, 33, -4, 77), 99);
145    assertEquals((int) mh.invokeExact(99, 111, 33, -4, 77, 88), 111);
146    assertEquals((int) mh.invokeExact(111, 33, -4, 77, 88, 99), 111);
147
148    // A preposterous number of arguments.
149    mh = MethodHandles.lookup().findStatic(
150        Main.class, "Min2Print26",
151        MethodType.methodType(
152            // Return-type
153            int.class,
154            // Arguments
155            int.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class,
156            int.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class,
157            int.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class,
158            int.class, int.class));
159    assertEquals(1, (int) mh.invokeExact(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
160                                         13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25));
161    assertEquals(25, (int) mh.invokeExact(25, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
162                                         13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24));
163    assertEquals(25, (int) mh.invokeExact(24, 25, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
164                                         13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23));
165
166    try {
167        // Wrong argument type
168        mh.invokeExact("a");
169        fail("No WMTE for wrong arguments");
170    } catch (WrongMethodTypeException wmte) {}
171
172    try {
173        // Invoke on null handle.
174        MethodHandle mh0 = null;
175        mh0.invokeExact("bad");
176        fail("No NPE for you");
177    } catch (NullPointerException npe) {}
178
179    System.out.println("BasicTest done.");
180  }
181
182  private static boolean And(boolean lhs, boolean rhs) {
183    return lhs & rhs;
184  }
185
186  private static boolean Xor(boolean lhs, boolean rhs) {
187    return lhs ^ rhs;
188  }
189
190  private static String Multiply(String value, int n) {
191    String result = "";
192    for (int i = 0; i < n; ++i) {
193      result = value + result;
194    }
195    return result;
196  }
197
198  private static byte Multiply(byte value, byte n) {
199    return (byte)(value * n);
200  }
201
202  private static short Multiply(short value, short n) {
203    return (short)(value * n);
204  }
205
206  private static int Multiply(int value, int n) {
207    return value * n;
208  }
209
210  private static long Multiply(long value, long n) {
211    return value * n;
212  }
213
214  private static float Multiply(float value, float n) {
215    return value * n;
216  }
217
218  private static double Multiply(double value, double n) {
219    return value * n;
220  }
221
222  private static char Next(char c) {
223    return (char)(c + 1);
224  }
225
226  public static void $opt$ReturnBooleanTest() throws Throwable {
227    MethodHandles.Lookup lookup = MethodHandles.lookup();
228    MethodHandle mh =
229            lookup.findStatic(Main.class, "And",
230                              MethodType.methodType(boolean.class, boolean.class, boolean.class));
231    assertEquals(true, (boolean) mh.invokeExact(true, true));
232    assertEquals(false, (boolean) mh.invokeExact(true, false));
233    assertEquals(false, (boolean) mh.invokeExact(false, true));
234    assertEquals(false, (boolean) mh.invokeExact(false, false));
235    assertEquals(true, (boolean) mh.invoke(true, true));
236    assertEquals(false, (boolean) mh.invoke(true, false));
237    assertEquals(false, (boolean) mh.invoke(false, true));
238    assertEquals(false, (boolean) mh.invoke(false, false));
239
240    mh = lookup.findStatic(Main.class, "Xor",
241                           MethodType.methodType(boolean.class, boolean.class, boolean.class));
242    assertEquals(false, (boolean) mh.invokeExact(true, true));
243    assertEquals(true, (boolean) mh.invokeExact(true, false));
244    assertEquals(true, (boolean) mh.invokeExact(false, true));
245    assertEquals(false, (boolean) mh.invokeExact(false, false));
246    assertEquals(false, (boolean) mh.invoke(true, true));
247    assertEquals(true, (boolean) mh.invoke(true, false));
248    assertEquals(true, (boolean) mh.invoke(false, true));
249    assertEquals(false, (boolean) mh.invoke(false, false));
250
251    System.out.println("$opt$ReturnBooleanTest done.");
252  }
253
254  public static void $opt$ReturnCharTest() throws Throwable {
255    MethodHandles.Lookup lookup = MethodHandles.lookup();
256    MethodHandle mh = lookup.findStatic(Main.class, "Next",
257                           MethodType.methodType(char.class, char.class));
258    assertEquals('B', (char) mh.invokeExact('A'));
259    assertEquals((char) -55, (char) mh.invokeExact((char) -56));
260    System.out.println("$opt$ReturnCharTest done.");
261  }
262
263  public static void $opt$ReturnByteTest() throws Throwable {
264    MethodHandles.Lookup lookup = MethodHandles.lookup();
265    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
266                                         MethodType.methodType(byte.class, byte.class, byte.class));
267    assertEquals((byte) 30, (byte) mh.invokeExact((byte) 10, (byte) 3));
268    assertEquals((byte) -90, (byte) mh.invoke((byte) -10, (byte) 9));
269    System.out.println("$opt$ReturnByteTest done.");
270  }
271
272  public static void $opt$ReturnShortTest() throws Throwable {
273    MethodHandles.Lookup lookup = MethodHandles.lookup();
274    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
275                           MethodType.methodType(short.class, short.class, short.class));
276    assertEquals((short) 3000, (short) mh.invokeExact((short) 1000, (short) 3));
277    assertEquals((short) -3000, (short) mh.invoke((short) -1000, (short) 3));
278    System.out.println("$opt$ReturnShortTest done.");
279  }
280
281  public static void $opt$ReturnIntTest() throws Throwable {
282    MethodHandles.Lookup lookup = MethodHandles.lookup();
283    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
284                           MethodType.methodType(int.class, int.class, int.class));
285    assertEquals(3_000_000, (int) mh.invokeExact(1_000_000, 3));
286    assertEquals(-3_000_000, (int) mh.invoke(-1_000, 3_000));
287    System.out.println("$opt$ReturnIntTest done.");
288  }
289
290  public static void $opt$ReturnLongTest() throws Throwable {
291    MethodHandles.Lookup lookup = MethodHandles.lookup();
292    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
293                           MethodType.methodType(long.class, long.class, long.class));
294    assertEquals(4_294_967_295_000L, (long) mh.invokeExact(1000L, 4_294_967_295L));
295    assertEquals(-4_294_967_295_000L, (long) mh.invoke(-1000L, 4_294_967_295L));
296    System.out.println("$opt$ReturnLongTest done.");
297  }
298
299  public static void $opt$ReturnFloatTest() throws Throwable {
300    MethodHandles.Lookup lookup = MethodHandles.lookup();
301    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
302                           MethodType.methodType(float.class, float.class, float.class));
303    assertEquals(3.0F, (float) mh.invokeExact(1000.0F, 3e-3F));
304    assertEquals(-3.0F, (float) mh.invoke(-1000.0F, 3e-3F));
305    System.out.println("$opt$ReturnFloatTest done.");
306  }
307
308  public static void $opt$ReturnDoubleTest() throws Throwable {
309    MethodHandles.Lookup lookup = MethodHandles.lookup();
310    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
311                           MethodType.methodType(double.class, double.class, double.class));
312    assertEquals(3033000.0, (double) mh.invokeExact(1000.0, 3.033e3));
313    assertEquals(-3033000.0, (double) mh.invoke(-1000.0, 3.033e3));
314    System.out.println("$opt$ReturnDoubleTest done.");
315  }
316
317  public static void $opt$ReturnStringTest() throws Throwable {
318    MethodHandles.Lookup lookup = MethodHandles.lookup();
319    MethodHandle mh = lookup.findStatic(Main.class, "Multiply",
320                           MethodType.methodType(String.class, String.class, int.class));
321    assertEquals("100010001000", (String) mh.invokeExact("1000", 3));
322    assertEquals("100010001000", (String) mh.invoke("1000", 3));
323    System.out.println("$opt$ReturnStringTest done.");
324  }
325
326  public static void ReturnValuesTest() throws Throwable {
327    $opt$ReturnBooleanTest();
328    $opt$ReturnCharTest();
329    $opt$ReturnByteTest();
330    $opt$ReturnShortTest();
331    $opt$ReturnIntTest();
332    $opt$ReturnLongTest();
333    $opt$ReturnFloatTest();
334    $opt$ReturnDoubleTest();
335    $opt$ReturnStringTest();
336    System.out.println("ReturnValuesTest done.");
337  }
338
339  static class ValueHolder {
340    public boolean m_z;
341    public static boolean s_z;
342  }
343
344  public static void $opt$AccessorsTest() throws Throwable {
345    ValueHolder valueHolder = new ValueHolder();
346    MethodHandles.Lookup lookup = MethodHandles.lookup();
347
348    MethodHandle setMember = lookup.findSetter(ValueHolder.class, "m_z", boolean.class);
349    MethodHandle getMember = lookup.findGetter(ValueHolder.class, "m_z", boolean.class);
350    MethodHandle setStatic = lookup.findStaticSetter(ValueHolder.class, "s_z", boolean.class);
351    MethodHandle getStatic = lookup.findStaticGetter(ValueHolder.class, "s_z", boolean.class);
352
353    boolean [] values = { false, true, false, true, false };
354    for (boolean value : values) {
355      assertEquals((boolean) getStatic.invoke(), ValueHolder.s_z);
356      setStatic.invoke(value);
357      ValueHolder.s_z = value;
358      assertEquals(ValueHolder.s_z, value);
359      assertEquals((boolean) getStatic.invoke(), value);
360
361      assertEquals((boolean) getMember.invoke(valueHolder), valueHolder.m_z);
362      setMember.invoke(valueHolder, value);
363      valueHolder.m_z = value;
364      assertEquals(valueHolder.m_z, value);
365      assertEquals((boolean) getMember.invoke(valueHolder), value);
366    }
367  }
368
369  public static void main(String[] args) throws Throwable {
370    $opt$BasicTest();
371    ReturnValuesTest();
372    $opt$AccessorsTest();
373  }
374}
375