xref: /aosp_15_r20/art/test/979-const-method-handle/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker import annotations.ConstantMethodHandle;
18*795d594fSAndroid Build Coastguard Worker import annotations.ConstantMethodType;
19*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.MethodHandle;
20*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.MethodType;
21*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.WrongMethodTypeException;
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker import java.io.StreamTokenizer;
24*795d594fSAndroid Build Coastguard Worker import java.io.StringReader;
25*795d594fSAndroid Build Coastguard Worker import java.util.Stack;
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker class Main {
28*795d594fSAndroid Build Coastguard Worker     /**
29*795d594fSAndroid Build Coastguard Worker      * Number of iterations run to attempt to trigger JIT compilation. These tests run on ART and
30*795d594fSAndroid Build Coastguard Worker      * the RI so they iterate rather than using the ART only native method ensureJitCompiled().
31*795d594fSAndroid Build Coastguard Worker      */
32*795d594fSAndroid Build Coastguard Worker     private static final int ITERATIONS_FOR_JIT = 30000;
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker     /** A static field updated by method handle getters and setters. */
35*795d594fSAndroid Build Coastguard Worker     private static String name = "default";
36*795d594fSAndroid Build Coastguard Worker 
unreachable()37*795d594fSAndroid Build Coastguard Worker     private static void unreachable() {
38*795d594fSAndroid Build Coastguard Worker         throw new Error("Unreachable");
39*795d594fSAndroid Build Coastguard Worker     }
40*795d594fSAndroid Build Coastguard Worker 
assertEquals(Object expected, Object actual)41*795d594fSAndroid Build Coastguard Worker     private static void assertEquals(Object expected, Object actual) {
42*795d594fSAndroid Build Coastguard Worker         if (!expected.equals(actual)) {
43*795d594fSAndroid Build Coastguard Worker             throw new AssertionError("Assertion failure: " + expected + " != " + actual);
44*795d594fSAndroid Build Coastguard Worker         }
45*795d594fSAndroid Build Coastguard Worker     }
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker     private static class LocalClass {
LocalClass()48*795d594fSAndroid Build Coastguard Worker         public LocalClass() {}
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker         private int field;
51*795d594fSAndroid Build Coastguard Worker     }
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker     private static class TestTokenizer extends StreamTokenizer {
TestTokenizer(String message)54*795d594fSAndroid Build Coastguard Worker         public TestTokenizer(String message) {
55*795d594fSAndroid Build Coastguard Worker             super(new StringReader(message));
56*795d594fSAndroid Build Coastguard Worker         }
57*795d594fSAndroid Build Coastguard Worker     }
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker     @ConstantMethodType(
60*795d594fSAndroid Build Coastguard Worker             returnType = String.class,
61*795d594fSAndroid Build Coastguard Worker             parameterTypes = {int.class, Integer.class, System.class})
methodType0()62*795d594fSAndroid Build Coastguard Worker     private static MethodType methodType0() {
63*795d594fSAndroid Build Coastguard Worker         unreachable();
64*795d594fSAndroid Build Coastguard Worker         return null;
65*795d594fSAndroid Build Coastguard Worker     }
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker     @ConstantMethodType(
68*795d594fSAndroid Build Coastguard Worker             returnType = void.class,
69*795d594fSAndroid Build Coastguard Worker             parameterTypes = {LocalClass.class})
methodType1()70*795d594fSAndroid Build Coastguard Worker     private static MethodType methodType1() {
71*795d594fSAndroid Build Coastguard Worker         unreachable();
72*795d594fSAndroid Build Coastguard Worker         return null;
73*795d594fSAndroid Build Coastguard Worker     }
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker     @ConstantMethodType(
76*795d594fSAndroid Build Coastguard Worker             returnType = void.class,
77*795d594fSAndroid Build Coastguard Worker             parameterTypes = {MissingType.class})
missingType()78*795d594fSAndroid Build Coastguard Worker     private static MethodType missingType() {
79*795d594fSAndroid Build Coastguard Worker         unreachable();
80*795d594fSAndroid Build Coastguard Worker         return null;
81*795d594fSAndroid Build Coastguard Worker     }
82*795d594fSAndroid Build Coastguard Worker 
repeatConstMethodType0(MethodType expected)83*795d594fSAndroid Build Coastguard Worker     private static void repeatConstMethodType0(MethodType expected) {
84*795d594fSAndroid Build Coastguard Worker         System.out.print("repeatConstMethodType0(");
85*795d594fSAndroid Build Coastguard Worker         System.out.print(expected);
86*795d594fSAndroid Build Coastguard Worker         System.out.println(")");
87*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
88*795d594fSAndroid Build Coastguard Worker             MethodType actual = methodType0();
89*795d594fSAndroid Build Coastguard Worker             assertEquals(expected, actual);
90*795d594fSAndroid Build Coastguard Worker         }
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker 
repeatConstMethodType1(MethodType expected)93*795d594fSAndroid Build Coastguard Worker     private static void repeatConstMethodType1(MethodType expected) {
94*795d594fSAndroid Build Coastguard Worker         System.out.print("repeatConstMethodType1(");
95*795d594fSAndroid Build Coastguard Worker         System.out.print(expected);
96*795d594fSAndroid Build Coastguard Worker         System.out.println(")");
97*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
98*795d594fSAndroid Build Coastguard Worker             MethodType actual = methodType1();
99*795d594fSAndroid Build Coastguard Worker             assertEquals(expected, actual);
100*795d594fSAndroid Build Coastguard Worker         }
101*795d594fSAndroid Build Coastguard Worker     }
102*795d594fSAndroid Build Coastguard Worker 
helloWorld(String who)103*795d594fSAndroid Build Coastguard Worker     static void helloWorld(String who) {
104*795d594fSAndroid Build Coastguard Worker         System.out.print("Hello World! And Hello ");
105*795d594fSAndroid Build Coastguard Worker         System.out.println(who);
106*795d594fSAndroid Build Coastguard Worker     }
107*795d594fSAndroid Build Coastguard Worker 
108*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
109*795d594fSAndroid Build Coastguard Worker             kind = ConstantMethodHandle.INVOKE_STATIC,
110*795d594fSAndroid Build Coastguard Worker             owner = "Main",
111*795d594fSAndroid Build Coastguard Worker             fieldOrMethodName = "helloWorld",
112*795d594fSAndroid Build Coastguard Worker             descriptor = "(Ljava/lang/String;)V")
printHelloHandle()113*795d594fSAndroid Build Coastguard Worker     private static MethodHandle printHelloHandle() {
114*795d594fSAndroid Build Coastguard Worker         unreachable();
115*795d594fSAndroid Build Coastguard Worker         return null;
116*795d594fSAndroid Build Coastguard Worker     }
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
119*795d594fSAndroid Build Coastguard Worker             kind = ConstantMethodHandle.STATIC_PUT,
120*795d594fSAndroid Build Coastguard Worker             owner = "Main",
121*795d594fSAndroid Build Coastguard Worker             fieldOrMethodName = "name",
122*795d594fSAndroid Build Coastguard Worker             descriptor = "Ljava/lang/String;")
setNameHandle()123*795d594fSAndroid Build Coastguard Worker     private static MethodHandle setNameHandle() {
124*795d594fSAndroid Build Coastguard Worker         unreachable();
125*795d594fSAndroid Build Coastguard Worker         return null;
126*795d594fSAndroid Build Coastguard Worker     }
127*795d594fSAndroid Build Coastguard Worker 
128*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
129*795d594fSAndroid Build Coastguard Worker             kind = ConstantMethodHandle.STATIC_GET,
130*795d594fSAndroid Build Coastguard Worker             owner = "Main",
131*795d594fSAndroid Build Coastguard Worker             fieldOrMethodName = "name",
132*795d594fSAndroid Build Coastguard Worker             descriptor = "Ljava/lang/String;")
getNameHandle()133*795d594fSAndroid Build Coastguard Worker     private static MethodHandle getNameHandle() {
134*795d594fSAndroid Build Coastguard Worker         unreachable();
135*795d594fSAndroid Build Coastguard Worker         return null;
136*795d594fSAndroid Build Coastguard Worker     }
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
139*795d594fSAndroid Build Coastguard Worker             kind = ConstantMethodHandle.STATIC_GET,
140*795d594fSAndroid Build Coastguard Worker             owner = "java/lang/Math",
141*795d594fSAndroid Build Coastguard Worker             fieldOrMethodName = "E",
142*795d594fSAndroid Build Coastguard Worker             descriptor = "D")
getMathE()143*795d594fSAndroid Build Coastguard Worker     private static MethodHandle getMathE() {
144*795d594fSAndroid Build Coastguard Worker         unreachable();
145*795d594fSAndroid Build Coastguard Worker         return null;
146*795d594fSAndroid Build Coastguard Worker     }
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
149*795d594fSAndroid Build Coastguard Worker             kind = ConstantMethodHandle.STATIC_PUT,
150*795d594fSAndroid Build Coastguard Worker             owner = "java/lang/Math",
151*795d594fSAndroid Build Coastguard Worker             fieldOrMethodName = "E",
152*795d594fSAndroid Build Coastguard Worker             descriptor = "D")
putMathE()153*795d594fSAndroid Build Coastguard Worker     private static MethodHandle putMathE() {
154*795d594fSAndroid Build Coastguard Worker         unreachable();
155*795d594fSAndroid Build Coastguard Worker         return null;
156*795d594fSAndroid Build Coastguard Worker     }
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
159*795d594fSAndroid Build Coastguard Worker         kind = ConstantMethodHandle.INSTANCE_GET,
160*795d594fSAndroid Build Coastguard Worker         owner = "java/io/StreamTokenizer",
161*795d594fSAndroid Build Coastguard Worker         fieldOrMethodName = "sval",
162*795d594fSAndroid Build Coastguard Worker         descriptor = "Ljava/lang/String;")
getSval()163*795d594fSAndroid Build Coastguard Worker      private static MethodHandle getSval() {
164*795d594fSAndroid Build Coastguard Worker         unreachable();
165*795d594fSAndroid Build Coastguard Worker         return null;
166*795d594fSAndroid Build Coastguard Worker     }
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker     // This constant-method-handle references a private instance field. If
169*795d594fSAndroid Build Coastguard Worker     // referenced in bytecode it raises IAE at load time.
170*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
171*795d594fSAndroid Build Coastguard Worker         kind = ConstantMethodHandle.INSTANCE_PUT,
172*795d594fSAndroid Build Coastguard Worker         owner = "java/io/StreamTokenizer",
173*795d594fSAndroid Build Coastguard Worker         fieldOrMethodName = "peekc",
174*795d594fSAndroid Build Coastguard Worker         descriptor = "I")
putPeekc()175*795d594fSAndroid Build Coastguard Worker      private static MethodHandle putPeekc() {
176*795d594fSAndroid Build Coastguard Worker         unreachable();
177*795d594fSAndroid Build Coastguard Worker         return null;
178*795d594fSAndroid Build Coastguard Worker     }
179*795d594fSAndroid Build Coastguard Worker 
180*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
181*795d594fSAndroid Build Coastguard Worker         kind = ConstantMethodHandle.INVOKE_VIRTUAL,
182*795d594fSAndroid Build Coastguard Worker         owner = "java/util/Stack",
183*795d594fSAndroid Build Coastguard Worker         fieldOrMethodName = "pop",
184*795d594fSAndroid Build Coastguard Worker         descriptor = "()Ljava/lang/Object;")
stackPop()185*795d594fSAndroid Build Coastguard Worker     private static MethodHandle stackPop() {
186*795d594fSAndroid Build Coastguard Worker         unreachable();
187*795d594fSAndroid Build Coastguard Worker         return null;
188*795d594fSAndroid Build Coastguard Worker     }
189*795d594fSAndroid Build Coastguard Worker 
190*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
191*795d594fSAndroid Build Coastguard Worker         kind = ConstantMethodHandle.INVOKE_VIRTUAL,
192*795d594fSAndroid Build Coastguard Worker         owner = "java/util/Stack",
193*795d594fSAndroid Build Coastguard Worker         fieldOrMethodName = "trimToSize",
194*795d594fSAndroid Build Coastguard Worker         descriptor = "()V")
stackTrim()195*795d594fSAndroid Build Coastguard Worker     private static MethodHandle stackTrim() {
196*795d594fSAndroid Build Coastguard Worker         unreachable();
197*795d594fSAndroid Build Coastguard Worker         return null;
198*795d594fSAndroid Build Coastguard Worker     }
199*795d594fSAndroid Build Coastguard Worker 
200*795d594fSAndroid Build Coastguard Worker     @ConstantMethodHandle(
201*795d594fSAndroid Build Coastguard Worker             kind = ConstantMethodHandle.STATIC_GET,
202*795d594fSAndroid Build Coastguard Worker             owner = "PrivateMember",
203*795d594fSAndroid Build Coastguard Worker             fieldOrMethodName = "privateField",
204*795d594fSAndroid Build Coastguard Worker             descriptor = "I")
getPrivateField()205*795d594fSAndroid Build Coastguard Worker     private static MethodHandle getPrivateField() {
206*795d594fSAndroid Build Coastguard Worker         unreachable();
207*795d594fSAndroid Build Coastguard Worker         return null;
208*795d594fSAndroid Build Coastguard Worker     }
209*795d594fSAndroid Build Coastguard Worker 
repeatConstMethodHandle()210*795d594fSAndroid Build Coastguard Worker     private static void repeatConstMethodHandle() throws Throwable {
211*795d594fSAndroid Build Coastguard Worker         System.out.println("repeatConstMethodHandle()");
212*795d594fSAndroid Build Coastguard Worker         String[] values = {"A", "B", "C"};
213*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
214*795d594fSAndroid Build Coastguard Worker             String value = values[i % values.length];
215*795d594fSAndroid Build Coastguard Worker             setNameHandle().invoke(value);
216*795d594fSAndroid Build Coastguard Worker             String actual = (String) getNameHandle().invokeExact();
217*795d594fSAndroid Build Coastguard Worker             assertEquals(value, actual);
218*795d594fSAndroid Build Coastguard Worker             assertEquals(value, name);
219*795d594fSAndroid Build Coastguard Worker         }
220*795d594fSAndroid Build Coastguard Worker     }
221*795d594fSAndroid Build Coastguard Worker 
main(String[] args)222*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Throwable {
223*795d594fSAndroid Build Coastguard Worker         System.out.println(methodType0());
224*795d594fSAndroid Build Coastguard Worker         repeatConstMethodType0(
225*795d594fSAndroid Build Coastguard Worker                 MethodType.methodType(String.class, int.class, Integer.class, System.class));
226*795d594fSAndroid Build Coastguard Worker         repeatConstMethodType1(MethodType.methodType(void.class, LocalClass.class));
227*795d594fSAndroid Build Coastguard Worker         printHelloHandle().invokeExact("Zog");
228*795d594fSAndroid Build Coastguard Worker         printHelloHandle().invokeExact("Zorba");
229*795d594fSAndroid Build Coastguard Worker         setNameHandle().invokeExact("HoverFly");
230*795d594fSAndroid Build Coastguard Worker         System.out.print("name is ");
231*795d594fSAndroid Build Coastguard Worker         System.out.println(name);
232*795d594fSAndroid Build Coastguard Worker         System.out.println(getMathE().invoke());
233*795d594fSAndroid Build Coastguard Worker         repeatConstMethodHandle();
234*795d594fSAndroid Build Coastguard Worker         try {
235*795d594fSAndroid Build Coastguard Worker             putMathE().invokeExact(Math.PI);
236*795d594fSAndroid Build Coastguard Worker             unreachable();
237*795d594fSAndroid Build Coastguard Worker         } catch (IllegalAccessError expected) {
238*795d594fSAndroid Build Coastguard Worker             System.out.println("Attempting to set Math.E raised IAE");
239*795d594fSAndroid Build Coastguard Worker         }
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker         StreamTokenizer st = new StreamTokenizer(new StringReader("Quack Moo Woof"));
242*795d594fSAndroid Build Coastguard Worker         while (st.nextToken() != StreamTokenizer.TT_EOF) {
243*795d594fSAndroid Build Coastguard Worker             System.out.println((String) getSval().invokeExact(st));
244*795d594fSAndroid Build Coastguard Worker         }
245*795d594fSAndroid Build Coastguard Worker 
246*795d594fSAndroid Build Coastguard Worker         TestTokenizer tt = new TestTokenizer("Test message 123");
247*795d594fSAndroid Build Coastguard Worker         tt.nextToken();
248*795d594fSAndroid Build Coastguard Worker         System.out.println((String) getSval().invoke(tt));
249*795d594fSAndroid Build Coastguard Worker         try {
250*795d594fSAndroid Build Coastguard Worker             System.out.println((String) getSval().invokeExact(tt));
251*795d594fSAndroid Build Coastguard Worker         } catch (WrongMethodTypeException wmte) {
252*795d594fSAndroid Build Coastguard Worker             System.out.println("Getting field in TestTokenizer raised WMTE (woohoo!)");
253*795d594fSAndroid Build Coastguard Worker         }
254*795d594fSAndroid Build Coastguard Worker 
255*795d594fSAndroid Build Coastguard Worker         Stack stack = new Stack();
256*795d594fSAndroid Build Coastguard Worker         stack.push(Integer.valueOf(3));
257*795d594fSAndroid Build Coastguard Worker         stack.push(Integer.valueOf(5));
258*795d594fSAndroid Build Coastguard Worker         stack.push(Integer.valueOf(7));
259*795d594fSAndroid Build Coastguard Worker         Object tos = stackPop().invokeExact(stack);
260*795d594fSAndroid Build Coastguard Worker         System.out.println("Stack: tos was " + tos);
261*795d594fSAndroid Build Coastguard Worker         System.out.println("Stack: capacity was " + stack.capacity());
262*795d594fSAndroid Build Coastguard Worker         stackTrim().invokeExact(stack);
263*795d594fSAndroid Build Coastguard Worker         System.out.println("Stack: capacity is " + stack.capacity());
264*795d594fSAndroid Build Coastguard Worker 
265*795d594fSAndroid Build Coastguard Worker         // We used to not report in the compiler that loading a ConstMethodHandle/ConstMethodType
266*795d594fSAndroid Build Coastguard Worker         // can throw, which meant we were not catching the exception in the situation where we
267*795d594fSAndroid Build Coastguard Worker         // inline the loading.
268*795d594fSAndroid Build Coastguard Worker         try {
269*795d594fSAndroid Build Coastguard Worker           $inline$getPrivateField();
270*795d594fSAndroid Build Coastguard Worker           System.out.println("Expected IllegalAccessError");
271*795d594fSAndroid Build Coastguard Worker         } catch (IllegalAccessError e) {
272*795d594fSAndroid Build Coastguard Worker           // expected
273*795d594fSAndroid Build Coastguard Worker         }
274*795d594fSAndroid Build Coastguard Worker 
275*795d594fSAndroid Build Coastguard Worker         try {
276*795d594fSAndroid Build Coastguard Worker           $inline$missingType();
277*795d594fSAndroid Build Coastguard Worker           System.out.println("Expected NoClassDefFoundError");
278*795d594fSAndroid Build Coastguard Worker         } catch (NoClassDefFoundError e) {
279*795d594fSAndroid Build Coastguard Worker           // expected
280*795d594fSAndroid Build Coastguard Worker         }
281*795d594fSAndroid Build Coastguard Worker     }
282*795d594fSAndroid Build Coastguard Worker 
$inline$getPrivateField()283*795d594fSAndroid Build Coastguard Worker     public static void $inline$getPrivateField() {
284*795d594fSAndroid Build Coastguard Worker       getPrivateField();
285*795d594fSAndroid Build Coastguard Worker     }
286*795d594fSAndroid Build Coastguard Worker 
$inline$missingType()287*795d594fSAndroid Build Coastguard Worker     public static void $inline$missingType() {
288*795d594fSAndroid Build Coastguard Worker       missingType();
289*795d594fSAndroid Build Coastguard Worker     }
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker 
292*795d594fSAndroid Build Coastguard Worker class PrivateMember {
293*795d594fSAndroid Build Coastguard Worker   private static int privateField;
294*795d594fSAndroid Build Coastguard Worker }
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker class MissingType {
297*795d594fSAndroid Build Coastguard Worker }
298