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 annotations.BootstrapMethod;
18 import annotations.CalledByIndy;
19 import java.lang.invoke.CallSite;
20 import java.lang.invoke.ConstantCallSite;
21 import java.lang.invoke.MethodHandle;
22 import java.lang.invoke.MethodHandles;
23 import java.lang.invoke.MethodType;
24 
25 class TestInvocationKinds extends TestBase {
26     private static int static_field;
27     private double instance_field;
28 
lookupStaticFieldGetter( MethodHandles.Lookup lookup, String name, MethodType methodType)29     static CallSite lookupStaticFieldGetter(
30             MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable {
31         // methodType = "()LfieldType;"
32         MethodHandle mh =
33                 lookup.findStaticGetter(TestInvocationKinds.class, name, methodType.returnType());
34         return new ConstantCallSite(mh);
35     }
36 
37     @CalledByIndy(
38         bootstrapMethod =
39                 @BootstrapMethod(
40                     enclosingType = TestInvocationKinds.class,
41                     name = "lookupStaticFieldSetter"
42                 ),
43         fieldOrMethodName = "static_field",
44         returnType = void.class,
45         parameterTypes = {int.class}
46     )
setStaticField(int value)47     private static void setStaticField(int value) {
48         assertNotReached();
49     }
50 
lookupStaticFieldSetter( MethodHandles.Lookup lookup, String name, MethodType methodType)51     static CallSite lookupStaticFieldSetter(
52             MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable {
53         // methodType = "(LfieldType;)V"
54         MethodHandle mh =
55                 lookup.findStaticSetter(
56                         TestInvocationKinds.class, name, methodType.parameterType(0));
57         return new ConstantCallSite(mh);
58     }
59 
60     @CalledByIndy(
61         bootstrapMethod =
62                 @BootstrapMethod(
63                     enclosingType = TestInvocationKinds.class,
64                     name = "lookupStaticFieldGetter"
65                 ),
66         fieldOrMethodName = "static_field",
67         returnType = int.class,
68         parameterTypes = {}
69     )
getStaticField()70     private static int getStaticField() {
71         assertNotReached();
72         return 0;
73     }
74 
lookupInstanceFieldSetter( MethodHandles.Lookup lookup, String name, MethodType methodType)75     static CallSite lookupInstanceFieldSetter(
76             MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable {
77         // methodType = "(Lreceiver;LfieldType;)V"
78         MethodHandle mh =
79                 lookup.findSetter(methodType.parameterType(0), name, methodType.parameterType(1));
80         return new ConstantCallSite(mh);
81     }
82 
83     @CalledByIndy(
84         bootstrapMethod =
85                 @BootstrapMethod(
86                     enclosingType = TestInvocationKinds.class,
87                     name = "lookupInstanceFieldSetter"
88                 ),
89         fieldOrMethodName = "instance_field",
90         returnType = void.class,
91         parameterTypes = {TestInvocationKinds.class, double.class}
92     )
setInstanceField(TestInvocationKinds instance, double value)93     private static void setInstanceField(TestInvocationKinds instance, double value) {
94         assertNotReached();
95         instance.instance_field = Double.NaN;
96     }
97 
lookupInstanceFieldGetter( MethodHandles.Lookup lookup, String name, MethodType methodType)98     static CallSite lookupInstanceFieldGetter(
99             MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable {
100         // methodType = "(Lreceiver;)LfieldType;"
101         MethodHandle mh =
102                 lookup.findGetter(methodType.parameterType(0), name, methodType.returnType());
103         return new ConstantCallSite(mh);
104     }
105 
106     @CalledByIndy(
107         bootstrapMethod =
108                 @BootstrapMethod(
109                     enclosingType = TestInvocationKinds.class,
110                     name = "lookupInstanceFieldGetter"
111                 ),
112         fieldOrMethodName = "instance_field",
113         returnType = double.class,
114         parameterTypes = {TestInvocationKinds.class}
115     )
getInstanceField(TestInvocationKinds instance)116     private static double getInstanceField(TestInvocationKinds instance) {
117         assertNotReached();
118         return Double.NaN;
119     }
120 
testStaticFieldAccessors()121     private static void testStaticFieldAccessors() {
122         System.out.println("testStaticFieldAccessors");
123         setStaticField(3);
124         assertEquals(static_field, 3);
125         setStaticField(4);
126         assertEquals(static_field, 4);
127         assertEquals(static_field, getStaticField());
128         static_field = Integer.MAX_VALUE;
129         assertEquals(Integer.MAX_VALUE, getStaticField());
130     }
131 
testInstanceFieldAccessors()132     private static void testInstanceFieldAccessors() {
133         System.out.println("testInstanceFieldAccessors");
134         TestInvocationKinds instance = new TestInvocationKinds();
135         instance.instance_field = Double.MIN_VALUE;
136         setInstanceField(instance, Math.PI);
137         assertEquals(Math.PI, instance.instance_field);
138         instance.instance_field = Math.E;
139         assertEquals(Math.E, getInstanceField(instance));
140     }
141 
lookupVirtual( MethodHandles.Lookup lookup, String name, MethodType methodType)142     private static CallSite lookupVirtual(
143             MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable {
144         // To get the point-of-use and invokedynamic to work the methodType here has the
145         // receiver type as the leading paramter which needs to be dropped for findVirtual().
146         MethodType mt = methodType.dropParameterTypes(0, 1);
147         MethodHandle mh = lookup.findVirtual(TestInvocationKinds.class, name, mt);
148         return new ConstantCallSite(mh);
149     }
150 
151     @CalledByIndy(
152         bootstrapMethod =
153                 @BootstrapMethod(enclosingType = TestInvocationKinds.class, name = "lookupVirtual"),
154         fieldOrMethodName = "getMaxIntegerValue",
155         returnType = int.class,
156         parameterTypes = {TestInvocationKinds.class, int.class, int.class}
157     )
maxIntegerValue(TestInvocationKinds receiver, int x, int y)158     private static int maxIntegerValue(TestInvocationKinds receiver, int x, int y) {
159         assertNotReached();
160         return 0;
161     }
162 
getMaxIntegerValue(int x, int y)163     public int getMaxIntegerValue(int x, int y) {
164         return x > y ? x : y;
165     }
166 
testInvokeVirtual()167     static void testInvokeVirtual() {
168         System.out.print("testInvokeVirtual => max(77, -3) = ");
169         TestInvocationKinds receiver = new TestInvocationKinds();
170         int result = maxIntegerValue(receiver, 77, -3);
171         System.out.println(result);
172     }
173 
174     static class Widget {
175         int value;
176 
Widget(int value)177         public Widget(int value) {}
178     }
179 
lookupConstructor( MethodHandles.Lookup lookup, String name, MethodType methodType)180     private static CallSite lookupConstructor(
181             MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable {
182         // methodType = (constructorParams);classToBeConstructed
183         Class<?> cls = methodType.returnType();
184         MethodType constructorMethodType = methodType.changeReturnType(void.class);
185         MethodHandle mh = lookup.findConstructor(cls, constructorMethodType);
186         return new ConstantCallSite(mh);
187     }
188 
189     @CalledByIndy(
190         bootstrapMethod =
191                 @BootstrapMethod(
192                     enclosingType = TestInvocationKinds.class,
193                     name = "lookupConstructor"
194                 ),
195         fieldOrMethodName = "unused",
196         returnType = Widget.class,
197         parameterTypes = {int.class}
198     )
makeWidget(int v)199     private static Widget makeWidget(int v) {
200         assertNotReached();
201         return null;
202     }
203 
testConstructor()204     static void testConstructor() {
205         System.out.print("testConstructor => ");
206         Widget receiver = makeWidget(3);
207         assertEquals(Widget.class, receiver.getClass());
208         System.out.println(receiver.getClass());
209     }
210 
test()211     public static void test() {
212         System.out.println(TestInvocationKinds.class.getName());
213         testStaticFieldAccessors();
214         testInstanceFieldAccessors();
215         testInvokeVirtual();
216         testConstructor();
217     }
218 }
219