/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import annotations.BootstrapMethod; import annotations.CalledByIndy; import annotations.Constant; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; public class TestBadBootstrapArguments extends TestBase { private static CallSite bsm( MethodHandles.Lookup lookup, String methodName, MethodType methodType, int extraInt, String extraString) throws Throwable { System.out.print("bsm("); System.out.print(lookup.lookupClass()); System.out.print(", "); System.out.print(methodName); System.out.print(", "); System.out.print(methodType); System.out.print(", "); System.out.print(extraInt); System.out.print(", "); System.out.print(extraString); System.out.println(")"); MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); return new ConstantCallSite(mh); } @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsm", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, int.class, String.class } ), fieldOrMethodName = "happy", constantArgumentsForBootstrapMethod = { @Constant(intValue = -1), @Constant(stringValue = "very") } ) private static void invokeHappy() { assertNotReached(); } private static void happy() { System.out.println("happy"); } // BootstrapMethod.parameterTypes != parameterTypesOf(constantArgumentsForBootstrapMethod) @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsm", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, int.class, double.class } ), fieldOrMethodName = "wrongParameterTypes", constantArgumentsForBootstrapMethod = { @Constant(intValue = -1), @Constant(stringValue = "very") } ) private static void invokeWrongParameterTypes() throws NoSuchMethodError { assertNotReached(); } private static void wrongParameterTypes() { System.out.println("wrongParameterTypes"); } // BootstrapMethod.parameterTypes != parameterTypesOf(constantArgumentsForBootstrapMethod) // (missing constantArgumentTypes)) @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsm", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, int.class, double.class } ), fieldOrMethodName = "missingParameterTypes", constantArgumentsForBootstrapMethod = {} ) private static void invokeMissingParameterTypes() throws NoSuchMethodError { assertNotReached(); } private static void missingParameterTypes() { System.out.println("missingParameterTypes"); } // BootstrapMethod.parameterTypes != parameterTypesOf(constantArgumentsForBootstrapMethod): // extra constant present @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsm", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, int.class, String.class } ), fieldOrMethodName = "extraArguments", constantArgumentsForBootstrapMethod = { @Constant(intValue = 1), @Constant(stringValue = "2"), @Constant(intValue = 3) } ) private static void invokeExtraArguments() { assertNotReached(); } private static void extraArguments() { System.out.println("extraArguments"); } // constantArgumentTypes do not correspond to expected parameter types @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsm", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, int.class, String.class } ), fieldOrMethodName = "wrongArguments", constantArgumentsForBootstrapMethod = { @Constant(stringValue = "1"), @Constant(doubleValue = Math.PI) } ) private static void invokeWrongArguments() { assertNotReached(); } private static void wrongArguments() { System.out.println("wrongArguments"); } // constantArgumentTypes do not correspond to expected parameter types @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsm", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, int.class, String.class } ), fieldOrMethodName = "wrongArgumentsAgain", constantArgumentsForBootstrapMethod = { @Constant(doubleValue = Math.PI), @Constant(stringValue = "pie") } ) private static void invokeWrongArgumentsAgain() { assertNotReached(); } private static void wrongArgumentsAgain() { System.out.println("wrongArgumentsAgain"); } // Primitive argument types not supported {Z, B, C, S}. private static CallSite bsmZBCS( MethodHandles.Lookup lookup, String methodName, MethodType methodType, boolean extraArg0, byte extraArg1, char extraArg2, short extraArg3) throws Throwable { assertNotReached(); return null; } // Arguments are narrower than supported. @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmZBCS", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, boolean.class, byte.class, char.class, short.class } ), fieldOrMethodName = "narrowArguments", constantArgumentsForBootstrapMethod = { @Constant(booleanValue = true), @Constant(byteValue = Byte.MAX_VALUE), @Constant(charValue = 'A'), @Constant(shortValue = Short.MIN_VALUE) } ) private static void invokeNarrowArguments() { assertNotReached(); } private static void narrowArguments() { assertNotReached(); } private static CallSite bsmDJ( MethodHandles.Lookup lookup, String methodName, MethodType methodType, double extraArg0, long extraArg1) throws Throwable { System.out.print("bsmDJ(..., "); System.out.print(extraArg0); System.out.print(", "); System.out.print(extraArg1); System.out.println(")"); MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); return new ConstantCallSite(mh); } // Arguments need widening to parameter types. @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmDJ", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, double.class, long.class } ), fieldOrMethodName = "wideningArguments", constantArgumentsForBootstrapMethod = { @Constant(doubleValue = Double.MAX_VALUE), @Constant(intValue = Integer.MAX_VALUE) } ) private static void invokeWideningArguments() { assertNotReached(); } private static void wideningArguments() { System.out.println("wideningArguments"); } private static CallSite bsmDoubleLong( MethodHandles.Lookup lookup, String methodName, MethodType methodType, Double extraArg0, Long extraArg1) throws Throwable { System.out.print("bsmDoubleLong(..., "); System.out.print(extraArg0); System.out.print(", "); System.out.print(extraArg1); System.out.println(")"); MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); return new ConstantCallSite(mh); } // Arguments need boxing to parameter types @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmDoubleLong", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, Double.class, Long.class } ), fieldOrMethodName = "boxingArguments", constantArgumentsForBootstrapMethod = { @Constant(doubleValue = Double.MAX_VALUE), @Constant(longValue = Long.MAX_VALUE) } ) private static void invokeBoxingArguments() { assertNotReached(); } private static void boxingArguments() { System.out.println("boxingArguments"); } // Arguments need widening and boxing to parameter types @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmDoubleLong", parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, Double.class, Long.class } ), fieldOrMethodName = "wideningBoxingArguments", constantArgumentsForBootstrapMethod = { @Constant(floatValue = Float.MAX_VALUE), @Constant(longValue = Integer.MAX_VALUE) } ) private static void invokeWideningBoxingArguments() { assertNotReached(); } private static void wideningBoxingArguments() { System.out.println("wideningBoxingArguments"); } static void bsmReturningVoid(MethodHandles.Lookup lookup, String name, MethodType type) { System.out.println("bsm returning void value."); } @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmReturningVoid", parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, returnType = void.class ), fieldOrMethodName = "voidReturnType" ) private static void invokeVoidReturnType() { assertNotReached(); } private static void voidReturnType() { assertNotReached(); } static Object bsmReturningObject(MethodHandles.Lookup lookup, String name, MethodType type) { System.out.println("bsm returning Object value."); return new Object(); } @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmReturningObject", parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, returnType = Object.class ), fieldOrMethodName = "ObjectReturnType" ) private static void invokeObjectReturnType() { assertNotReached(); } private static void objectReturnType() { assertNotReached(); } static Integer bsmReturningInteger(MethodHandles.Lookup lookup, String name, MethodType type) { System.out.println("bsm returning Integer value."); return Integer.valueOf(3); } @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmReturningInteger", parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, returnType = Integer.class ), fieldOrMethodName = "integerReturnType" ) private static void invokeIntegerReturnType() { assertNotReached(); } private static void integerReturnType() { assertNotReached(); } static class TestersConstantCallSite extends ConstantCallSite { public TestersConstantCallSite(MethodHandle mh) { super(mh); } } static TestersConstantCallSite bsmReturningTestersConstantCallsite( MethodHandles.Lookup lookup, String name, MethodType type) throws Throwable { return new TestersConstantCallSite(lookup.findStatic(lookup.lookupClass(), name, type)); } @CalledByIndy( bootstrapMethod = @BootstrapMethod( enclosingType = TestBadBootstrapArguments.class, name = "bsmReturningTestersConstantCallsite", parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, returnType = TestersConstantCallSite.class ), fieldOrMethodName = "sayHello" ) private static void invokeViaCustomCallSiteClass() { assertNotReached(); } private static void sayHello() { System.out.println("Hello!"); } static void test() { System.out.println("TestBadBootstrapArguments"); invokeHappy(); try { invokeWrongParameterTypes(); assertNotReached(); } catch (NoSuchMethodError expected) { System.out.print("invokeWrongParameterTypes => "); System.out.println(expected.getClass()); } try { invokeMissingParameterTypes(); assertNotReached(); } catch (NoSuchMethodError expected) { System.out.print("invokeMissingParameterTypes => "); System.out.println(expected.getClass()); } try { invokeExtraArguments(); assertNotReached(); } catch (BootstrapMethodError expected) { assertEquals(WrongMethodTypeException.class, expected.getCause().getClass()); System.out.print("invokeExtraArguments => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeWrongArguments(); assertNotReached(); } catch (BootstrapMethodError expected) { assertEquals(ClassCastException.class, expected.getCause().getClass()); System.out.print("invokeWrongArguments => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeWrongArguments(); assertNotReached(); } catch (BootstrapMethodError expected) { assertEquals(ClassCastException.class, expected.getCause().getClass()); System.out.print("invokeWrongArguments => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeWrongArgumentsAgain(); assertNotReached(); } catch (BootstrapMethodError expected) { assertEquals(ClassCastException.class, expected.getCause().getClass()); System.out.print("invokeWrongArgumentsAgain => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeNarrowArguments(); assertNotReached(); } catch (BootstrapMethodError expected) { assertEquals(ClassCastException.class, expected.getCause().getClass()); System.out.print("invokeNarrowArguments => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } invokeWideningArguments(); invokeBoxingArguments(); try { invokeWideningBoxingArguments(); assertNotReached(); } catch (BootstrapMethodError expected) { System.out.print("invokeWideningBoxingArguments => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeVoidReturnType(); assertNotReached(); } catch (BootstrapMethodError expected) { System.out.print("invokeVoidReturnType() => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeObjectReturnType(); assertNotReached(); } catch (BootstrapMethodError expected) { System.out.print("invokeObjectReturnType() => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } try { invokeIntegerReturnType(); assertNotReached(); } catch (BootstrapMethodError expected) { System.out.print("invokeIntegerReturnType() => "); System.out.print(expected.getClass()); System.out.print(" => "); System.out.println(expected.getCause().getClass()); } invokeViaCustomCallSiteClass(); } }