diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/952-invoke-custom/expected.txt | 64 | ||||
| -rw-r--r-- | test/952-invoke-custom/src/Main.java | 11 | ||||
| -rw-r--r-- | test/952-invoke-custom/src/TestBadBootstrapArguments.java | 583 | ||||
| -rw-r--r-- | test/952-invoke-custom/src/TestDynamicBootstrapArguments.java | 92 | ||||
| -rw-r--r-- | test/952-invoke-custom/src/TestInvocationKinds.java | 1 | ||||
| -rw-r--r-- | test/952-invoke-custom/src/TestVariableArityLinkerMethod.java | 569 | ||||
| -rw-r--r-- | test/knownfailures.json | 1 |
7 files changed, 1313 insertions, 8 deletions
diff --git a/test/952-invoke-custom/expected.txt b/test/952-invoke-custom/expected.txt index 767cc7e734..7e8ffa6f41 100644 --- a/test/952-invoke-custom/expected.txt +++ b/test/952-invoke-custom/expected.txt @@ -18,3 +18,67 @@ testStaticFieldAccessors testInstanceFieldAccessors testInvokeVirtual => max(77, -3) = 77 testConstructor => class TestInvocationKinds$Widget +TestDynamicArguments +bsm +0, One, 3.141592653589793 +bsm +1, Two, 2.718281828459045 +bsm +2, Three, 0.0 +0, One, 3.141592653589793 +1, Two, 2.718281828459045 +2, Three, 0.0 +TestBadBootstrapArguments +bsm(class TestBadBootstrapArguments, happy, ()void, -1, very) +happy +invokeWrongParameterTypes => class java.lang.NoSuchMethodError +invokeMissingParameterTypes => class java.lang.NoSuchMethodError +invokeExtraArguments => class java.lang.BootstrapMethodError => class java.lang.invoke.WrongMethodTypeException +invokeWrongArguments => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +invokeWrongArguments => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +invokeWrongArgumentsAgain => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +invokeNarrowArguments => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +bsmDJ(..., 1.7976931348623157E308, 2147483647) +wideningArguments +bsmDoubleLong(..., 1.7976931348623157E308, 9223372036854775807) +boxingArguments +invokeWideningBoxingArguments => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +bsm returning void value. +invokeVoidReturnType() => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +bsm returning Object value. +invokeObjectReturnType() => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +bsm returning Integer value. +invokeIntegerReturnType() => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +Hello! +bsmWithStringArray(TestVariableArityLinkerMethod, methodA, ()void, [Aachen, Aalborg, Aalto]); +methodA +bsmWithStringArray(TestVariableArityLinkerMethod, methodB, ()void, [barium]); +methodB +bsmWithStringArray(TestVariableArityLinkerMethod, methodC, ()void, []); +methodC +methodA +methodB +methodC +bsmWithIntAndStringArray(TestVariableArityLinkerMethod, methodD, ()void, 101, [zoo, zoogene, zoogenic]); +methodD +bsmWithIntAndStringArray(TestVariableArityLinkerMethod, methodE, ()void, 102, [zonic]); +methodE +bsmWithIntAndStringArray(TestVariableArityLinkerMethod, methodF, ()void, 103, []); +methodF +methodD +methodE +methodF +bsmWithLongAndIntArray(TestVariableArityLinkerMethod, methodG, ()void, 81985529216486895, [1, -1, 2, -2]); +methodG +bsmWithFloatAndLongArray(TestVariableArityLinkerMethod, methodH, ()void, -2.7182817, [999999999999, -8888888888888]); +methodH +bsmWithClassAndFloatArray(TestVariableArityLinkerMethod, methodI, ()void, class java.lang.Throwable, [3.4028235E38, 1.4E-45, 3.1415927, -3.1415927]); +methodI +bsmWithDoubleArray(TestVariableArityLinkerMethod, methodJ, ()void, [1.7976931348623157E308, 4.9E-324, 2.718281828459045, -3.141592653589793]); +methodJ +bsmWithClassArray(TestVariableArityLinkerMethod, methodK, ()void, [class java.lang.Integer, class java.lang.invoke.MethodHandles, class java.util.Arrays]); +methodK +methodO => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +methodP => class java.lang.BootstrapMethodError => class java.lang.ClassCastException +methodQ => class java.lang.BootstrapMethodError => class java.lang.invoke.WrongMethodTypeException +methodR => class java.lang.BootstrapMethodError => class java.lang.invoke.WrongMethodTypeException diff --git a/test/952-invoke-custom/src/Main.java b/test/952-invoke-custom/src/Main.java index 0b1c1fffe5..d2250a9647 100644 --- a/test/952-invoke-custom/src/Main.java +++ b/test/952-invoke-custom/src/Main.java @@ -74,18 +74,15 @@ public class Main extends TestBase { TestLinkerMethodMinimalArguments.FAILURE_TYPE_NONE, 10, 13); } - private static void TestInvokeCustomWithConcurrentThreads() throws Throwable { - // This is a concurrency test that attempts to run invoke-custom on the same - // call site. - TestInvokeCustomWithConcurrentThreads.test(); - } - public static void main(String[] args) throws Throwable { TestUninitializedCallSite(); TestLinkerMethodMinimalArguments(); TestLinkerMethodMultipleArgumentTypes(); TestLinkerUnrelatedBSM.test(); - TestInvokeCustomWithConcurrentThreads(); + TestInvokeCustomWithConcurrentThreads.test(); TestInvocationKinds.test(); + TestDynamicBootstrapArguments.test(); + TestBadBootstrapArguments.test(); + TestVariableArityLinkerMethod.test(); } } diff --git a/test/952-invoke-custom/src/TestBadBootstrapArguments.java b/test/952-invoke-custom/src/TestBadBootstrapArguments.java new file mode 100644 index 0000000000..25d8b59eaa --- /dev/null +++ b/test/952-invoke-custom/src/TestBadBootstrapArguments.java @@ -0,0 +1,583 @@ +/* + * 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(); + } +} diff --git a/test/952-invoke-custom/src/TestDynamicBootstrapArguments.java b/test/952-invoke-custom/src/TestDynamicBootstrapArguments.java new file mode 100644 index 0000000000..782feca6da --- /dev/null +++ b/test/952-invoke-custom/src/TestDynamicBootstrapArguments.java @@ -0,0 +1,92 @@ +/* + * 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; + +class TestDynamicBootstrapArguments extends TestBase { + private static int bsmCalls = 0; + + static CallSite bsm( + MethodHandles.Lookup lookup, + String name, + MethodType methodType, + String otherNameComponent, + long nameSuffix) + throws Throwable { + bsmCalls = bsmCalls + 1; + Class<?> definingClass = TestDynamicBootstrapArguments.class; + String methodName = name + otherNameComponent + nameSuffix; + MethodHandle mh = lookup.findStatic(definingClass, methodName, methodType); + System.out.println("bsm"); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestDynamicBootstrapArguments.class, + name = "bsm", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + String.class, + long.class + } + ), + fieldOrMethodName = "target", + returnType = int.class, + parameterTypes = {int.class, String.class, double.class}, + constantArgumentsForBootstrapMethod = { + @Constant(stringValue = "A"), + @Constant(longValue = 100000000l) + } + ) + private static int testDynamic(int i, String s, Double d) { + assertNotReached(); + return 0; + } + + private static int targetA100000000(int i, String s, Double d) { + System.out.print(i); + System.out.print(", "); + System.out.print(s); + System.out.print(", "); + System.out.println(d); + return i; + } + + static void testCallSites() { + assertEquals(0, testDynamic(0, "One", Math.PI)); + assertEquals(1, testDynamic(1, "Two", Math.E)); + assertEquals(2, testDynamic(2, "Three", 0.0)); + } + + static void test() { + System.out.println("TestDynamicArguments"); + testCallSites(); + assertEquals(3, bsmCalls); + testCallSites(); + assertEquals(3, bsmCalls); + } +} diff --git a/test/952-invoke-custom/src/TestInvocationKinds.java b/test/952-invoke-custom/src/TestInvocationKinds.java index 7b88c18c66..f743bef158 100644 --- a/test/952-invoke-custom/src/TestInvocationKinds.java +++ b/test/952-invoke-custom/src/TestInvocationKinds.java @@ -173,6 +173,7 @@ class TestInvocationKinds extends TestBase { static class Widget { int value; + public Widget(int value) {} } diff --git a/test/952-invoke-custom/src/TestVariableArityLinkerMethod.java b/test/952-invoke-custom/src/TestVariableArityLinkerMethod.java new file mode 100644 index 0000000000..597273c8ec --- /dev/null +++ b/test/952-invoke-custom/src/TestVariableArityLinkerMethod.java @@ -0,0 +1,569 @@ +/* + * 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.util.Arrays; + +public class TestVariableArityLinkerMethod extends TestBase { + private static void printBsmArgs(String method, Object... args) { + System.out.print(method); + System.out.print("("); + for (int i = 0; i < args.length; ++i) { + if (i != 0) { + System.out.print(", "); + } + if (args[i] != null && args[i].getClass().isArray()) { + Object array = args[i]; + if (array.getClass() == int[].class) { + System.out.print(Arrays.toString((int[]) array)); + } else if (array.getClass() == long[].class) { + System.out.print(Arrays.toString((long[]) array)); + } else if (array.getClass() == float[].class) { + System.out.print(Arrays.toString((float[]) array)); + } else if (array.getClass() == double[].class) { + System.out.print(Arrays.toString((double[]) array)); + } else { + System.out.print(Arrays.toString((Object[]) array)); + } + } else { + System.out.print(args[i]); + } + } + System.out.println(");"); + } + + private static CallSite bsmWithStringArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + String... arityArgs) + throws Throwable { + printBsmArgs("bsmWithStringArray", lookup, methodName, methodType, arityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + String[].class + } + ), + fieldOrMethodName = "methodA", + constantArgumentsForBootstrapMethod = { + @Constant(stringValue = "Aachen"), + @Constant(stringValue = "Aalborg"), + @Constant(stringValue = "Aalto") + } + ) + private static void methodA() { + System.out.println("methodA"); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + String[].class + } + ), + fieldOrMethodName = "methodB", + constantArgumentsForBootstrapMethod = {@Constant(stringValue = "barium")} + ) + private static void methodB() { + System.out.println("methodB"); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + String[].class + } + ), + fieldOrMethodName = "methodC" + ) + private static void methodC() { + System.out.println("methodC"); + } + + private static CallSite bsmWithIntAndStringArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + int extraInt, + String... extraArityArgs) + throws Throwable { + printBsmArgs( + "bsmWithIntAndStringArray", + lookup, + methodName, + methodType, + extraInt, + extraArityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithIntAndStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + int.class, + String[].class + } + ), + fieldOrMethodName = "methodD", + constantArgumentsForBootstrapMethod = { + @Constant(intValue = 101), + @Constant(stringValue = "zoo"), + @Constant(stringValue = "zoogene"), + @Constant(stringValue = "zoogenic") + } + ) + private static void methodD() { + System.out.println("methodD"); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithIntAndStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + int.class, + String[].class + } + ), + fieldOrMethodName = "methodE", + constantArgumentsForBootstrapMethod = { + @Constant(intValue = 102), + @Constant(stringValue = "zonic") + } + ) + private static void methodE() { + System.out.println("methodE"); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithIntAndStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + int.class, + String[].class + } + ), + fieldOrMethodName = "methodF", + constantArgumentsForBootstrapMethod = {@Constant(intValue = 103)} + ) + private static void methodF() { + System.out.println("methodF"); + } + + private static CallSite bsmWithLongAndIntArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + long extraArg, + int... arityArgs) + throws Throwable { + printBsmArgs("bsmWithLongAndIntArray", lookup, methodName, methodType, extraArg, arityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithLongAndIntArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + long.class, + int[].class + } + ), + fieldOrMethodName = "methodG", + constantArgumentsForBootstrapMethod = { + @Constant(longValue = 0x123456789abcdefl), + @Constant(intValue = +1), + @Constant(intValue = -1), + @Constant(intValue = +2), + @Constant(intValue = -2) + } + ) + private static void methodG() { + System.out.println("methodG"); + } + + private static CallSite bsmWithFloatAndLongArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + float extraArg, + long... arityArgs) + throws Throwable { + printBsmArgs( + "bsmWithFloatAndLongArray", lookup, methodName, methodType, extraArg, arityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithFloatAndLongArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + float.class, + long[].class + } + ), + fieldOrMethodName = "methodH", + constantArgumentsForBootstrapMethod = { + @Constant(floatValue = (float) -Math.E), + @Constant(longValue = 999999999999l), + @Constant(longValue = -8888888888888l) + } + ) + private static void methodH() { + System.out.println("methodH"); + } + + private static CallSite bsmWithClassAndFloatArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + Class<?> extraArg, + float... arityArgs) + throws Throwable { + printBsmArgs( + "bsmWithClassAndFloatArray", lookup, methodName, methodType, extraArg, arityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithClassAndFloatArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + Class.class, + float[].class + } + ), + fieldOrMethodName = "methodI", + constantArgumentsForBootstrapMethod = { + @Constant(classValue = Throwable.class), + @Constant(floatValue = Float.MAX_VALUE), + @Constant(floatValue = Float.MIN_VALUE), + @Constant(floatValue = (float) Math.PI), + @Constant(floatValue = (float) -Math.PI) + } + ) + private static void methodI() { + System.out.println("methodI"); + } + + private static CallSite bsmWithDoubleArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + double... arityArgs) + throws Throwable { + printBsmArgs("bsmWithDoubleArray", lookup, methodName, methodType, arityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithDoubleArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + double[].class + } + ), + fieldOrMethodName = "methodJ", + constantArgumentsForBootstrapMethod = { + @Constant(doubleValue = Double.MAX_VALUE), + @Constant(doubleValue = Double.MIN_VALUE), + @Constant(doubleValue = Math.E), + @Constant(doubleValue = -Math.PI) + } + ) + private static void methodJ() { + System.out.println("methodJ"); + } + + private static CallSite bsmWithClassArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + Class... arityArgs) + throws Throwable { + printBsmArgs("bsmWithClassArray", lookup, methodName, methodType, arityArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithClassArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + Class[].class + } + ), + fieldOrMethodName = "methodK", + constantArgumentsForBootstrapMethod = { + @Constant(classValue = Integer.class), + @Constant(classValue = MethodHandles.class), + @Constant(classValue = Arrays.class) + } + ) + private static void methodK() { + System.out.println("methodK"); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithIntAndStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + int.class, + String[].class + } + ), + fieldOrMethodName = "methodO", + constantArgumentsForBootstrapMethod = {@Constant(intValue = 103), @Constant(intValue = 104)} + ) + private static void methodO() { + // Arguments are not compatible + assertNotReached(); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithIntAndStringArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + int.class, + String[].class + } + ), + fieldOrMethodName = "methodP", + constantArgumentsForBootstrapMethod = { + @Constant(intValue = 103), + @Constant(stringValue = "A"), + @Constant(stringValue = "B"), + @Constant(intValue = 42) + } + ) + private static void methodP() { + // Arguments are not compatible - specifically, the third + // component of potential collector array is an integer + // argument (42). + assertNotReached(); + } + + private static CallSite bsmWithWiderArray( + MethodHandles.Lookup lookup, String methodName, MethodType methodType, long[] extraArgs) + throws Throwable { + printBsmArgs("bsmWithWiderArray", lookup, methodName, methodType, extraArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithWiderArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + long[].class + } + ), + fieldOrMethodName = "methodQ", + constantArgumentsForBootstrapMethod = {@Constant(intValue = 103), @Constant(intValue = 42)} + ) + private static void methodQ() { + assertNotReached(); + } + + private static CallSite bsmWithBoxedArray( + MethodHandles.Lookup lookup, + String methodName, + MethodType methodType, + Integer[] extraArgs) + throws Throwable { + printBsmArgs("bsmWithBoxedArray", lookup, methodName, methodType, extraArgs); + MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestVariableArityLinkerMethod.class, + name = "bsmWithBoxedArray", + parameterTypes = { + MethodHandles.Lookup.class, + String.class, + MethodType.class, + Integer[].class + } + ), + fieldOrMethodName = "methodR", + constantArgumentsForBootstrapMethod = { + @Constant(intValue = 1030), + @Constant(intValue = 420) + } + ) + private static void methodR() { + assertNotReached(); + } + + static void test() { + // Happy cases + for (int i = 0; i < 2; ++i) { + methodA(); + methodB(); + methodC(); + } + for (int i = 0; i < 2; ++i) { + methodD(); + methodE(); + methodF(); + } + methodG(); + methodH(); + methodI(); + methodJ(); + methodK(); + + // Broken cases + try { + // bsm has incompatible static methods. Collector + // component type is String, the corresponding static + // arguments are int values. + methodO(); + assertNotReached(); + } catch (BootstrapMethodError expected) { + System.out.print("methodO => "); + System.out.print(expected.getClass()); + System.out.print(" => "); + System.out.println(expected.getCause().getClass()); + } + try { + // bsm has a trailing String array for the collector array. + // There is an int value amongst the String values. + methodP(); + assertNotReached(); + } catch (BootstrapMethodError expected) { + System.out.print("methodP => "); + System.out.print(expected.getClass()); + System.out.print(" => "); + System.out.println(expected.getCause().getClass()); + } + try { + // bsm has as trailing long[] element for the collector array. + // The corresponding static bsm arguments are of type int. + methodQ(); + assertNotReached(); + } catch (BootstrapMethodError expected) { + System.out.print("methodQ => "); + System.out.print(expected.getClass()); + System.out.print(" => "); + System.out.println(expected.getCause().getClass()); + } + try { + // bsm has as trailing Integer[] element for the collector array. + // The corresponding static bsm arguments are of type int. + methodR(); + assertNotReached(); + } catch (BootstrapMethodError expected) { + System.out.print("methodR => "); + System.out.print(expected.getClass()); + System.out.print(" => "); + System.out.println(expected.getCause().getClass()); + } + } +} diff --git a/test/knownfailures.json b/test/knownfailures.json index 5fb78191ef..b2f579d3b9 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -934,7 +934,6 @@ "946-obsolete-throw", "948-change-annotations", "950-redefine-intrinsic", - "952-invoke-custom", "954-invoke-polymorphic-verifier", "955-methodhandles-smali", "956-methodhandles", |