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 annotations.Constant;
20 import java.lang.invoke.CallSite;
21 import java.lang.invoke.ConstantCallSite;
22 import java.lang.invoke.MethodHandle;
23 import java.lang.invoke.MethodHandles;
24 import java.lang.invoke.MethodType;
25 import java.lang.invoke.WrongMethodTypeException;
26 
27 public class TestBadBootstrapArguments extends TestBase {
bsm( MethodHandles.Lookup lookup, String methodName, MethodType methodType, int extraInt, String extraString)28     private static CallSite bsm(
29             MethodHandles.Lookup lookup,
30             String methodName,
31             MethodType methodType,
32             int extraInt,
33             String extraString)
34             throws Throwable {
35         System.out.print("bsm(");
36         System.out.print(lookup.lookupClass());
37         System.out.print(", ");
38         System.out.print(methodName);
39         System.out.print(", ");
40         System.out.print(methodType);
41         System.out.print(", ");
42         System.out.print(extraInt);
43         System.out.print(", ");
44         System.out.print(extraString);
45         System.out.println(")");
46         MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType);
47         return new ConstantCallSite(mh);
48     }
49 
50     @CalledByIndy(
51         bootstrapMethod =
52                 @BootstrapMethod(
53                     enclosingType = TestBadBootstrapArguments.class,
54                     name = "bsm",
55                     parameterTypes = {
56                         MethodHandles.Lookup.class,
57                         String.class,
58                         MethodType.class,
59                         int.class,
60                         String.class
61                     }
62                 ),
63         fieldOrMethodName = "happy",
64         constantArgumentsForBootstrapMethod = {
65             @Constant(intValue = -1),
66             @Constant(stringValue = "very")
67         }
68     )
invokeHappy()69     private static void invokeHappy() {
70         assertNotReached();
71     }
72 
happy()73     private static void happy() {
74         System.out.println("happy");
75     }
76 
77     // BootstrapMethod.parameterTypes != parameterTypesOf(constantArgumentsForBootstrapMethod)
78     @CalledByIndy(
79         bootstrapMethod =
80                 @BootstrapMethod(
81                     enclosingType = TestBadBootstrapArguments.class,
82                     name = "bsm",
83                     parameterTypes = {
84                         MethodHandles.Lookup.class,
85                         String.class,
86                         MethodType.class,
87                         int.class,
88                         double.class
89                     }
90                 ),
91         fieldOrMethodName = "wrongParameterTypes",
92         constantArgumentsForBootstrapMethod = {
93             @Constant(intValue = -1),
94             @Constant(stringValue = "very")
95         }
96     )
invokeWrongParameterTypes()97     private static void invokeWrongParameterTypes() throws NoSuchMethodError {
98         assertNotReached();
99     }
100 
wrongParameterTypes()101     private static void wrongParameterTypes() {
102         System.out.println("wrongParameterTypes");
103     }
104 
105     // BootstrapMethod.parameterTypes != parameterTypesOf(constantArgumentsForBootstrapMethod)
106     // (missing constantArgumentTypes))
107     @CalledByIndy(
108         bootstrapMethod =
109                 @BootstrapMethod(
110                     enclosingType = TestBadBootstrapArguments.class,
111                     name = "bsm",
112                     parameterTypes = {
113                         MethodHandles.Lookup.class,
114                         String.class,
115                         MethodType.class,
116                         int.class,
117                         double.class
118                     }
119                 ),
120         fieldOrMethodName = "missingParameterTypes",
121         constantArgumentsForBootstrapMethod = {}
122     )
invokeMissingParameterTypes()123     private static void invokeMissingParameterTypes() throws NoSuchMethodError {
124         assertNotReached();
125     }
126 
missingParameterTypes()127     private static void missingParameterTypes() {
128         System.out.println("missingParameterTypes");
129     }
130 
131     // BootstrapMethod.parameterTypes != parameterTypesOf(constantArgumentsForBootstrapMethod):
132     // extra constant present
133     @CalledByIndy(
134         bootstrapMethod =
135                 @BootstrapMethod(
136                     enclosingType = TestBadBootstrapArguments.class,
137                     name = "bsm",
138                     parameterTypes = {
139                         MethodHandles.Lookup.class,
140                         String.class,
141                         MethodType.class,
142                         int.class,
143                         String.class
144                     }
145                 ),
146         fieldOrMethodName = "extraArguments",
147         constantArgumentsForBootstrapMethod = {
148             @Constant(intValue = 1),
149             @Constant(stringValue = "2"),
150             @Constant(intValue = 3)
151         }
152     )
invokeExtraArguments()153     private static void invokeExtraArguments() {
154         assertNotReached();
155     }
156 
extraArguments()157     private static void extraArguments() {
158         System.out.println("extraArguments");
159     }
160 
161     // constantArgumentTypes do not correspond to expected parameter types
162     @CalledByIndy(
163         bootstrapMethod =
164                 @BootstrapMethod(
165                     enclosingType = TestBadBootstrapArguments.class,
166                     name = "bsm",
167                     parameterTypes = {
168                         MethodHandles.Lookup.class,
169                         String.class,
170                         MethodType.class,
171                         int.class,
172                         String.class
173                     }
174                 ),
175         fieldOrMethodName = "wrongArguments",
176         constantArgumentsForBootstrapMethod = {
177             @Constant(stringValue = "1"),
178             @Constant(doubleValue = Math.PI)
179         }
180     )
invokeWrongArguments()181     private static void invokeWrongArguments() {
182         assertNotReached();
183     }
184 
wrongArguments()185     private static void wrongArguments() {
186         System.out.println("wrongArguments");
187     }
188 
189     // constantArgumentTypes do not correspond to expected parameter types
190     @CalledByIndy(
191         bootstrapMethod =
192                 @BootstrapMethod(
193                     enclosingType = TestBadBootstrapArguments.class,
194                     name = "bsm",
195                     parameterTypes = {
196                         MethodHandles.Lookup.class,
197                         String.class,
198                         MethodType.class,
199                         int.class,
200                         String.class
201                     }
202                 ),
203         fieldOrMethodName = "wrongArgumentsAgain",
204         constantArgumentsForBootstrapMethod = {
205             @Constant(doubleValue = Math.PI),
206             @Constant(stringValue = "pie")
207         }
208     )
invokeWrongArgumentsAgain()209     private static void invokeWrongArgumentsAgain() {
210         assertNotReached();
211     }
212 
wrongArgumentsAgain()213     private static void wrongArgumentsAgain() {
214         System.out.println("wrongArgumentsAgain");
215     }
216 
217     // Primitive argument types not supported {Z, B, C, S}.
bsmZBCS( MethodHandles.Lookup lookup, String methodName, MethodType methodType, boolean extraArg0, byte extraArg1, char extraArg2, short extraArg3)218     private static CallSite bsmZBCS(
219             MethodHandles.Lookup lookup,
220             String methodName,
221             MethodType methodType,
222             boolean extraArg0,
223             byte extraArg1,
224             char extraArg2,
225             short extraArg3)
226             throws Throwable {
227         assertNotReached();
228         return null;
229     }
230 
231     // Arguments are narrower than supported.
232     @CalledByIndy(
233         bootstrapMethod =
234                 @BootstrapMethod(
235                     enclosingType = TestBadBootstrapArguments.class,
236                     name = "bsmZBCS",
237                     parameterTypes = {
238                         MethodHandles.Lookup.class,
239                         String.class,
240                         MethodType.class,
241                         boolean.class,
242                         byte.class,
243                         char.class,
244                         short.class
245                     }
246                 ),
247         fieldOrMethodName = "narrowArguments",
248         constantArgumentsForBootstrapMethod = {
249             @Constant(booleanValue = true),
250             @Constant(byteValue = Byte.MAX_VALUE),
251             @Constant(charValue = 'A'),
252             @Constant(shortValue = Short.MIN_VALUE)
253         }
254     )
invokeNarrowArguments()255     private static void invokeNarrowArguments() {
256         assertNotReached();
257     }
258 
narrowArguments()259     private static void narrowArguments() {
260         assertNotReached();
261     }
262 
bsmDJ( MethodHandles.Lookup lookup, String methodName, MethodType methodType, double extraArg0, long extraArg1)263     private static CallSite bsmDJ(
264             MethodHandles.Lookup lookup,
265             String methodName,
266             MethodType methodType,
267             double extraArg0,
268             long extraArg1)
269             throws Throwable {
270         System.out.print("bsmDJ(..., ");
271         System.out.print(extraArg0);
272         System.out.print(", ");
273         System.out.print(extraArg1);
274         System.out.println(")");
275         MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType);
276         return new ConstantCallSite(mh);
277     }
278 
279     // Arguments need widening to parameter types.
280     @CalledByIndy(
281         bootstrapMethod =
282                 @BootstrapMethod(
283                     enclosingType = TestBadBootstrapArguments.class,
284                     name = "bsmDJ",
285                     parameterTypes = {
286                         MethodHandles.Lookup.class,
287                         String.class,
288                         MethodType.class,
289                         double.class,
290                         long.class
291                     }
292                 ),
293         fieldOrMethodName = "wideningArguments",
294         constantArgumentsForBootstrapMethod = {
295             @Constant(doubleValue = Double.MAX_VALUE),
296             @Constant(intValue = Integer.MAX_VALUE)
297         }
298     )
invokeWideningArguments()299     private static void invokeWideningArguments() {
300         assertNotReached();
301     }
302 
wideningArguments()303     private static void wideningArguments() {
304         System.out.println("wideningArguments");
305     }
306 
bsmDoubleLong( MethodHandles.Lookup lookup, String methodName, MethodType methodType, Double extraArg0, Long extraArg1)307     private static CallSite bsmDoubleLong(
308             MethodHandles.Lookup lookup,
309             String methodName,
310             MethodType methodType,
311             Double extraArg0,
312             Long extraArg1)
313             throws Throwable {
314         System.out.print("bsmDoubleLong(..., ");
315         System.out.print(extraArg0);
316         System.out.print(", ");
317         System.out.print(extraArg1);
318         System.out.println(")");
319         MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType);
320         return new ConstantCallSite(mh);
321     }
322 
323     // Arguments need boxing to parameter types
324     @CalledByIndy(
325         bootstrapMethod =
326                 @BootstrapMethod(
327                     enclosingType = TestBadBootstrapArguments.class,
328                     name = "bsmDoubleLong",
329                     parameterTypes = {
330                         MethodHandles.Lookup.class,
331                         String.class,
332                         MethodType.class,
333                         Double.class,
334                         Long.class
335                     }
336                 ),
337         fieldOrMethodName = "boxingArguments",
338         constantArgumentsForBootstrapMethod = {
339             @Constant(doubleValue = Double.MAX_VALUE),
340             @Constant(longValue = Long.MAX_VALUE)
341         }
342     )
invokeBoxingArguments()343     private static void invokeBoxingArguments() {
344         assertNotReached();
345     }
346 
boxingArguments()347     private static void boxingArguments() {
348         System.out.println("boxingArguments");
349     }
350 
351     // Arguments need widening and boxing to parameter types
352     @CalledByIndy(
353         bootstrapMethod =
354                 @BootstrapMethod(
355                     enclosingType = TestBadBootstrapArguments.class,
356                     name = "bsmDoubleLong",
357                     parameterTypes = {
358                         MethodHandles.Lookup.class,
359                         String.class,
360                         MethodType.class,
361                         Double.class,
362                         Long.class
363                     }
364                 ),
365         fieldOrMethodName = "wideningBoxingArguments",
366         constantArgumentsForBootstrapMethod = {
367             @Constant(floatValue = Float.MAX_VALUE),
368             @Constant(longValue = Integer.MAX_VALUE)
369         }
370     )
invokeWideningBoxingArguments()371     private static void invokeWideningBoxingArguments() {
372         assertNotReached();
373     }
374 
wideningBoxingArguments()375     private static void wideningBoxingArguments() {
376         System.out.println("wideningBoxingArguments");
377     }
378 
bsmReturningVoid(MethodHandles.Lookup lookup, String name, MethodType type)379     static void bsmReturningVoid(MethodHandles.Lookup lookup, String name, MethodType type) {
380         System.out.println("bsm returning void value.");
381     }
382 
383     @CalledByIndy(
384         bootstrapMethod =
385                 @BootstrapMethod(
386                     enclosingType = TestBadBootstrapArguments.class,
387                     name = "bsmReturningVoid",
388                     parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class},
389                     returnType = void.class
390                 ),
391         fieldOrMethodName = "voidReturnType"
392     )
invokeVoidReturnType()393     private static void invokeVoidReturnType() {
394         assertNotReached();
395     }
396 
voidReturnType()397     private static void voidReturnType() {
398         assertNotReached();
399     }
400 
bsmReturningObject(MethodHandles.Lookup lookup, String name, MethodType type)401     static Object bsmReturningObject(MethodHandles.Lookup lookup, String name, MethodType type) {
402         System.out.println("bsm returning Object value.");
403         return new Object();
404     }
405 
406     @CalledByIndy(
407         bootstrapMethod =
408                 @BootstrapMethod(
409                     enclosingType = TestBadBootstrapArguments.class,
410                     name = "bsmReturningObject",
411                     parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class},
412                     returnType = Object.class
413                 ),
414         fieldOrMethodName = "ObjectReturnType"
415     )
invokeObjectReturnType()416     private static void invokeObjectReturnType() {
417         assertNotReached();
418     }
419 
objectReturnType()420     private static void objectReturnType() {
421         assertNotReached();
422     }
423 
bsmReturningInteger(MethodHandles.Lookup lookup, String name, MethodType type)424     static Integer bsmReturningInteger(MethodHandles.Lookup lookup, String name, MethodType type) {
425         System.out.println("bsm returning Integer value.");
426         return Integer.valueOf(3);
427     }
428 
429     @CalledByIndy(
430         bootstrapMethod =
431                 @BootstrapMethod(
432                     enclosingType = TestBadBootstrapArguments.class,
433                     name = "bsmReturningInteger",
434                     parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class},
435                     returnType = Integer.class
436                 ),
437         fieldOrMethodName = "integerReturnType"
438     )
invokeIntegerReturnType()439     private static void invokeIntegerReturnType() {
440         assertNotReached();
441     }
442 
integerReturnType()443     private static void integerReturnType() {
444         assertNotReached();
445     }
446 
447     static class TestersConstantCallSite extends ConstantCallSite {
TestersConstantCallSite(MethodHandle mh)448         public TestersConstantCallSite(MethodHandle mh) {
449             super(mh);
450         }
451     }
452 
bsmReturningTestersConstantCallsite( MethodHandles.Lookup lookup, String name, MethodType type)453     static TestersConstantCallSite bsmReturningTestersConstantCallsite(
454             MethodHandles.Lookup lookup, String name, MethodType type) throws Throwable {
455         return new TestersConstantCallSite(lookup.findStatic(lookup.lookupClass(), name, type));
456     }
457 
458     @CalledByIndy(
459         bootstrapMethod =
460                 @BootstrapMethod(
461                     enclosingType = TestBadBootstrapArguments.class,
462                     name = "bsmReturningTestersConstantCallsite",
463                     parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class},
464                     returnType = TestersConstantCallSite.class
465                 ),
466         fieldOrMethodName = "sayHello"
467     )
invokeViaCustomCallSiteClass()468     private static void invokeViaCustomCallSiteClass() {
469         assertNotReached();
470     }
471 
sayHello()472     private static void sayHello() {
473         System.out.println("Hello!");
474     }
475 
test()476     static void test() {
477         System.out.println("TestBadBootstrapArguments");
478         invokeHappy();
479         try {
480             invokeWrongParameterTypes();
481             assertNotReached();
482         } catch (NoSuchMethodError expected) {
483             System.out.print("invokeWrongParameterTypes => ");
484             System.out.println(expected.getClass());
485         }
486         try {
487             invokeMissingParameterTypes();
488             assertNotReached();
489         } catch (NoSuchMethodError expected) {
490             System.out.print("invokeMissingParameterTypes => ");
491             System.out.println(expected.getClass());
492         }
493         try {
494             invokeExtraArguments();
495             assertNotReached();
496         } catch (BootstrapMethodError expected) {
497             assertEquals(WrongMethodTypeException.class, expected.getCause().getClass());
498             System.out.print("invokeExtraArguments => ");
499             System.out.print(expected.getClass());
500             System.out.print(" => ");
501             System.out.println(expected.getCause().getClass());
502         }
503         try {
504             invokeWrongArguments();
505             assertNotReached();
506         } catch (BootstrapMethodError expected) {
507             assertEquals(ClassCastException.class, expected.getCause().getClass());
508             System.out.print("invokeWrongArguments => ");
509             System.out.print(expected.getClass());
510             System.out.print(" => ");
511             System.out.println(expected.getCause().getClass());
512         }
513         try {
514             invokeWrongArguments();
515             assertNotReached();
516         } catch (BootstrapMethodError expected) {
517             assertEquals(ClassCastException.class, expected.getCause().getClass());
518             System.out.print("invokeWrongArguments => ");
519             System.out.print(expected.getClass());
520             System.out.print(" => ");
521             System.out.println(expected.getCause().getClass());
522         }
523         try {
524             invokeWrongArgumentsAgain();
525             assertNotReached();
526         } catch (BootstrapMethodError expected) {
527             assertEquals(ClassCastException.class, expected.getCause().getClass());
528             System.out.print("invokeWrongArgumentsAgain => ");
529             System.out.print(expected.getClass());
530             System.out.print(" => ");
531             System.out.println(expected.getCause().getClass());
532         }
533         try {
534             invokeNarrowArguments();
535             assertNotReached();
536         } catch (BootstrapMethodError expected) {
537             assertEquals(ClassCastException.class, expected.getCause().getClass());
538             System.out.print("invokeNarrowArguments => ");
539             System.out.print(expected.getClass());
540             System.out.print(" => ");
541             System.out.println(expected.getCause().getClass());
542         }
543         invokeWideningArguments();
544         invokeBoxingArguments();
545         try {
546             invokeWideningBoxingArguments();
547             assertNotReached();
548         } catch (BootstrapMethodError expected) {
549             System.out.print("invokeWideningBoxingArguments => ");
550             System.out.print(expected.getClass());
551             System.out.print(" => ");
552             System.out.println(expected.getCause().getClass());
553         }
554         try {
555             invokeVoidReturnType();
556             assertNotReached();
557         } catch (BootstrapMethodError expected) {
558             System.out.print("invokeVoidReturnType() => ");
559             System.out.print(expected.getClass());
560             System.out.print(" => ");
561             System.out.println(expected.getCause().getClass());
562         }
563         try {
564             invokeObjectReturnType();
565             assertNotReached();
566         } catch (BootstrapMethodError expected) {
567             System.out.print("invokeObjectReturnType() => ");
568             System.out.print(expected.getClass());
569             System.out.print(" => ");
570             System.out.println(expected.getCause().getClass());
571         }
572         try {
573             invokeIntegerReturnType();
574             assertNotReached();
575         } catch (BootstrapMethodError expected) {
576             System.out.print("invokeIntegerReturnType() => ");
577             System.out.print(expected.getClass());
578             System.out.print(" => ");
579             System.out.println(expected.getCause().getClass());
580         }
581         invokeViaCustomCallSiteClass();
582     }
583 }
584