blob: c0067d69193f4c66b58f5eefe8dc095c7411412b [file] [log] [blame]
// 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 com.android.tools.r8.NeverMerge;
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.
}
@NeverMerge
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);
}
}
}