| // Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8.cf; |
| |
| import java.lang.invoke.MethodHandle; |
| import java.lang.invoke.MethodHandles; |
| import java.lang.invoke.MethodType; |
| |
| public class MethodHandleTest { |
| |
| public static class C { |
| public C(int i) { |
| System.out.println("C " + i); |
| } |
| |
| public C() { |
| System.out.println("C"); |
| } |
| |
| public int vi; |
| public static int si; |
| |
| public static void svi(int i) { |
| System.out.println("svi " + i); |
| } |
| |
| public static long sji(int i) { |
| System.out.println("sji " + i); |
| return 42L; |
| } |
| |
| public static void svic(int i, char c) { |
| System.out.println("svic " + i); |
| } |
| |
| public static long sjic(int i, char c) { |
| System.out.println("sjic " + i); |
| return 42L; |
| } |
| |
| public void vvi(int i) { |
| System.out.println("vvi " + i); |
| } |
| |
| public long vji(int i) { |
| System.out.println("vji " + i); |
| return 42L; |
| } |
| |
| public void vvic(int i, char c) { |
| System.out.println("vvic " + i); |
| } |
| |
| public long vjic(int i, char c) { |
| System.out.println("vjic " + i); |
| return 42L; |
| } |
| } |
| |
| public static class D extends C { |
| public static MethodHandle vcviSpecialMethod() { |
| try { |
| return MethodHandles.lookup().findSpecial(C.class, "vvi", viType(), D.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public void vvi(int i) { |
| // Overridden to output nothing. |
| } |
| } |
| |
| public static class E { |
| // Class that is only mentioned in parameter list of LDC(MethodType)-instruction. |
| } |
| |
| public static class F { |
| // Class that is only mentioned in return value of LDC(MethodType)-instruction. |
| } |
| |
| public interface I { |
| int ii = 42; |
| |
| static void svi(int i) { |
| System.out.println("svi " + i); |
| } |
| |
| static long sji(int i) { |
| System.out.println("sji " + i); |
| return 42L; |
| } |
| |
| static void svic(int i, char c) { |
| System.out.println("svic " + i); |
| } |
| |
| static long sjic(int i, char c) { |
| System.out.println("sjic " + i); |
| return 42L; |
| } |
| |
| default void dvi(int i) { |
| System.out.println("dvi " + i); |
| } |
| |
| default long dji(int i) { |
| System.out.println("dji " + i); |
| return 42L; |
| } |
| |
| default void dvic(int i, char c) { |
| System.out.println("dvic " + i); |
| } |
| |
| default long djic(int i, char c) { |
| System.out.println("djic " + i); |
| return 42L; |
| } |
| } |
| |
| public static class Impl implements I {} |
| |
| public static void main(String[] args) { |
| // When MethodHandleTestRunner invokes this program with the JVM, "fail" is passed as arg. |
| // When invoked with Art, no arg is passed since interface fields may be modified on Art. |
| String expectedResult = args[0]; |
| C c = new C(42); |
| I i = new Impl(); |
| try { |
| scviMethod().invoke(1); |
| assertEquals(42L, (long) scjiMethod().invoke(2)); |
| scvicMethod().invoke(3, 'x'); |
| assertEquals(42L, (long) scjicMethod().invoke(4, 'x')); |
| vcviMethod().invoke(c, 5); |
| assertEquals(42L, (long) vcjiMethod().invoke(c, 6)); |
| vcvicMethod().invoke(c, 7, 'x'); |
| assertEquals(42L, (long) vcjicMethod().invoke(c, 8, 'x')); |
| siviMethod().invoke(9); |
| assertEquals(42L, (long) sijiMethod().invoke(10)); |
| sivicMethod().invoke(11, 'x'); |
| assertEquals(42L, (long) sijicMethod().invoke(12, 'x')); |
| diviMethod().invoke(i, 13); |
| assertEquals(42L, (long) dijiMethod().invoke(i, 14)); |
| divicMethod().invoke(i, 15, 'x'); |
| assertEquals(42L, (long) dijicMethod().invoke(i, 16, 'x')); |
| vciSetField().invoke(c, 17); |
| assertEquals(17, (int) vciGetField().invoke(c)); |
| sciSetField().invoke(18); |
| assertEquals(18, (int) sciGetField().invoke()); |
| String interfaceSetResult; |
| try { |
| iiSetField().invoke(19); |
| interfaceSetResult = "pass"; |
| } catch (RuntimeException e) { |
| if (e.getCause() instanceof IllegalAccessException) { |
| interfaceSetResult = "exception"; |
| } else { |
| throw e; |
| } |
| } catch (IllegalAccessError e) { |
| interfaceSetResult = "error"; |
| } |
| if (!interfaceSetResult.equals(expectedResult)) { |
| throw new RuntimeException( |
| "Wrong outcome of iiSetField().invoke(): Expected " |
| + expectedResult |
| + " but got " |
| + interfaceSetResult); |
| } |
| assertEquals(interfaceSetResult.equals("pass") ? 19 : 42, (int) iiGetField().invoke()); |
| MethodHandle methodHandle = D.vcviSpecialMethod(); |
| methodHandle.invoke(new D(), 20); |
| constructorMethod().invoke(21); |
| System.out.println(veType().parameterType(0).getName().lastIndexOf('.')); |
| System.out.println(fType().returnType().getName().lastIndexOf('.')); |
| } catch (Throwable e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private static void assertEquals(long l, long x) { |
| if (l != x) { |
| throw new AssertionError("Not equal: " + l + " != " + x); |
| } |
| } |
| |
| private static void assertEquals(int l, int x) { |
| if (l != x) { |
| throw new AssertionError("Not equal: " + l + " != " + x); |
| } |
| } |
| |
| public static MethodType viType() { |
| return MethodType.methodType(void.class, int.class); |
| } |
| |
| public static MethodType jiType() { |
| return MethodType.methodType(long.class, int.class); |
| } |
| |
| public static MethodType vicType() { |
| return MethodType.methodType(void.class, int.class, char.class); |
| } |
| |
| public static MethodType jicType() { |
| return MethodType.methodType(long.class, int.class, char.class); |
| } |
| |
| public static MethodType veType() { |
| return MethodType.methodType(void.class, E.class); |
| } |
| |
| public static MethodType fType() { |
| return MethodType.methodType(F.class); |
| } |
| |
| public static MethodHandle scviMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(C.class, "svi", viType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle scjiMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(C.class, "sji", jiType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle scvicMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(C.class, "svic", vicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle scjicMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(C.class, "sjic", jicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle vcviMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(C.class, "vvi", viType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle vcjiMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(C.class, "vji", jiType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle vcvicMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(C.class, "vvic", vicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle vcjicMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(C.class, "vjic", jicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle siviMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(I.class, "svi", viType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle sijiMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(I.class, "sji", jiType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle sivicMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(I.class, "svic", vicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle sijicMethod() { |
| try { |
| return MethodHandles.lookup().findStatic(I.class, "sjic", jicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle diviMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(I.class, "dvi", viType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle dijiMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(I.class, "dji", jiType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle divicMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(I.class, "dvic", vicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle dijicMethod() { |
| try { |
| return MethodHandles.lookup().findVirtual(I.class, "djic", jicType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle vciSetField() { |
| try { |
| return MethodHandles.lookup().findSetter(C.class, "vi", int.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle sciSetField() { |
| try { |
| return MethodHandles.lookup().findStaticSetter(C.class, "si", int.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle vciGetField() { |
| try { |
| return MethodHandles.lookup().findGetter(C.class, "vi", int.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle sciGetField() { |
| try { |
| return MethodHandles.lookup().findStaticGetter(C.class, "si", int.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle iiSetField() { |
| try { |
| return MethodHandles.lookup().findStaticSetter(I.class, "ii", int.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle iiGetField() { |
| try { |
| return MethodHandles.lookup().findStaticGetter(I.class, "ii", int.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static MethodHandle constructorMethod() { |
| try { |
| return MethodHandles.lookup().findConstructor(C.class, viType()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |