diff options
author | 2018-02-26 10:25:41 +0000 | |
---|---|---|
committer | 2018-02-27 10:05:34 +0000 | |
commit | 4c213cbf29048bb3df0065c17e82084a4afafc85 (patch) | |
tree | e9dcb78de802e2e54a431b2d1945ded6b96fd389 | |
parent | c57b3ae06f78b7386b6866a1ea265b3c790026dc (diff) |
ART: More refactoring of invoke-custom tests
Moves 952-invoke-custom-kinds into 952-invoke-custom using ASM
annotations to generate the necessary bootstrap metadata.
Simplify the annotations used by the transformer by replacing
MethodHandleKind, LinkerFieldHandle, and LinkerMethodHandle
annotations with BootstrapMethod annotation.
Bug: 73807070
Test: art/test/run-test --host 952
Change-Id: Ia85e79dea105d84ceaac7c6634b74a7eb232d0ee
24 files changed, 311 insertions, 280 deletions
diff --git a/test/952-invoke-custom-kinds/build b/test/952-invoke-custom-kinds/build deleted file mode 100644 index a02cdc3769..0000000000 --- a/test/952-invoke-custom-kinds/build +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2017 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. - -# Stop if something fails. -set -e - -${DX} --dex --min-sdk-version=26 --output=classes.dex classes - -zip $TEST_NAME.jar classes.dex diff --git a/test/952-invoke-custom-kinds/classes/Main.class b/test/952-invoke-custom-kinds/classes/Main.class Binary files differdeleted file mode 100644 index 6bc04e326a..0000000000 --- a/test/952-invoke-custom-kinds/classes/Main.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class b/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class Binary files differdeleted file mode 100644 index 5dfe958795..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class b/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class Binary files differdeleted file mode 100644 index a11ee696bf..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class Binary files differdeleted file mode 100644 index e233febbf4..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class Binary files differdeleted file mode 100644 index 41e1d431f2..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class Binary files differdeleted file mode 100644 index b8dcd5559a..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/Super.class b/test/952-invoke-custom-kinds/classes/invokecustom/Super.class Binary files differdeleted file mode 100644 index 7906f99d2d..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/Super.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class Binary files differdeleted file mode 100644 index c3266e49f7..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class Binary files differdeleted file mode 100644 index 03dc23396c..0000000000 --- a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class +++ /dev/null diff --git a/test/952-invoke-custom-kinds/expected.txt b/test/952-invoke-custom-kinds/expected.txt deleted file mode 100644 index c41b5c6d88..0000000000 --- a/test/952-invoke-custom-kinds/expected.txt +++ /dev/null @@ -1,40 +0,0 @@ -bsmLookupStatic [] -Hello World! -bsmLookupStatic [] -true -127 -c -1024 -123456 -1.2 -123456789 -3.5123456789 -String -bsmLookupStaticWithExtraArgs [1, 123456789, 123.456, 123456.789123] -targetMethodTest3 from InvokeCustom -bsmCreateCallSite [MethodHandle(InvokeCustom)void] -targetMethodTest4 from Super -bsmLookupStatic [] -targetMethodTest5 1000 + -923 = 77 -targetMethodTest5 returned: 77 -bsmLookupStatic [] -targetMethodTest6 8209686820727 + -1172812402961 = 7036874417766 -targetMethodTest6 returned: 7036874417766 -bsmLookupStatic [] -targetMethodTest7 0.50097656 * -0.50097656 = -0.2509775161743164 -targetMethodTest6 returned: -0.2509775161743164 -bsmLookupStatic [] -targetMethodTest8 First invokedynamic invocation -bsmLookupStatic [] -targetMethodTest8 Second invokedynamic invocation -bsmLookupStatic [] -targetMethodTest8 Dupe first invokedynamic invocation -bsmLookupTest9 [MethodHandle()int, MethodHandle(int)void, MethodHandle(InvokeCustom)float, MethodHandle(InvokeCustom,float)void] -targetMethodTest9 ()void -checkStaticFieldTest9: old 0 new 1985229328 expected 1985229328 OK -checkFieldTest9: old 0.0 new 1.99E-19 expected 1.99E-19 OK -helperMethodTest9 in class invokecustom.InvokeCustom -InvokeCustom.<init>(3) -run() for Test9 -InvokeCustom.privateMethodTest9() -targetMethodTest9() diff --git a/test/952-invoke-custom-kinds/info.txt b/test/952-invoke-custom-kinds/info.txt deleted file mode 100644 index 33b4cffc1d..0000000000 --- a/test/952-invoke-custom-kinds/info.txt +++ /dev/null @@ -1,4 +0,0 @@ -This test checks call sites and constant method handles in DEX files used -by invoke-custom. - -The class files come from dalvik/dx/tests/135-invoke-custom. diff --git a/test/952-invoke-custom/expected.txt b/test/952-invoke-custom/expected.txt index be01c453fb..767cc7e734 100644 --- a/test/952-invoke-custom/expected.txt +++ b/test/952-invoke-custom/expected.txt @@ -13,3 +13,8 @@ Linking _add (int,int)int 9000 TestLinkerUnrelatedBSM Winners 1 Votes 16 +TestInvocationKinds +testStaticFieldAccessors +testInstanceFieldAccessors +testInvokeVirtual => max(77, -3) = 77 +testConstructor => class TestInvocationKinds$Widget diff --git a/test/952-invoke-custom/src/Main.java b/test/952-invoke-custom/src/Main.java index 2e1db8200f..0b1c1fffe5 100644 --- a/test/952-invoke-custom/src/Main.java +++ b/test/952-invoke-custom/src/Main.java @@ -86,5 +86,6 @@ public class Main extends TestBase { TestLinkerMethodMultipleArgumentTypes(); TestLinkerUnrelatedBSM.test(); TestInvokeCustomWithConcurrentThreads(); + TestInvocationKinds.test(); } } diff --git a/test/952-invoke-custom/src/TestInvocationKinds.java b/test/952-invoke-custom/src/TestInvocationKinds.java new file mode 100644 index 0000000000..7b88c18c66 --- /dev/null +++ b/test/952-invoke-custom/src/TestInvocationKinds.java @@ -0,0 +1,217 @@ +/* + * 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 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 TestInvocationKinds extends TestBase { + private static int static_field; + private double instance_field; + + static CallSite lookupStaticFieldGetter( + MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable { + // methodType = "()LfieldType;" + MethodHandle mh = + lookup.findStaticGetter(TestInvocationKinds.class, name, methodType.returnType()); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestInvocationKinds.class, + name = "lookupStaticFieldSetter" + ), + fieldOrMethodName = "static_field", + returnType = void.class, + parameterTypes = {int.class} + ) + private static void setStaticField(int value) { + assertNotReached(); + } + + static CallSite lookupStaticFieldSetter( + MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable { + // methodType = "(LfieldType;)V" + MethodHandle mh = + lookup.findStaticSetter( + TestInvocationKinds.class, name, methodType.parameterType(0)); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestInvocationKinds.class, + name = "lookupStaticFieldGetter" + ), + fieldOrMethodName = "static_field", + returnType = int.class, + parameterTypes = {} + ) + private static int getStaticField() { + assertNotReached(); + return 0; + } + + static CallSite lookupInstanceFieldSetter( + MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable { + // methodType = "(Lreceiver;LfieldType;)V" + MethodHandle mh = + lookup.findSetter(methodType.parameterType(0), name, methodType.parameterType(1)); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestInvocationKinds.class, + name = "lookupInstanceFieldSetter" + ), + fieldOrMethodName = "instance_field", + returnType = void.class, + parameterTypes = {TestInvocationKinds.class, double.class} + ) + private static void setInstanceField(TestInvocationKinds instance, double value) { + assertNotReached(); + instance.instance_field = Double.NaN; + } + + static CallSite lookupInstanceFieldGetter( + MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable { + // methodType = "(Lreceiver;)LfieldType;" + MethodHandle mh = + lookup.findGetter(methodType.parameterType(0), name, methodType.returnType()); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestInvocationKinds.class, + name = "lookupInstanceFieldGetter" + ), + fieldOrMethodName = "instance_field", + returnType = double.class, + parameterTypes = {TestInvocationKinds.class} + ) + private static double getInstanceField(TestInvocationKinds instance) { + assertNotReached(); + return Double.NaN; + } + + private static void testStaticFieldAccessors() { + System.out.println("testStaticFieldAccessors"); + setStaticField(3); + assertEquals(static_field, 3); + setStaticField(4); + assertEquals(static_field, 4); + assertEquals(static_field, getStaticField()); + static_field = Integer.MAX_VALUE; + assertEquals(Integer.MAX_VALUE, getStaticField()); + } + + private static void testInstanceFieldAccessors() { + System.out.println("testInstanceFieldAccessors"); + TestInvocationKinds instance = new TestInvocationKinds(); + instance.instance_field = Double.MIN_VALUE; + setInstanceField(instance, Math.PI); + assertEquals(Math.PI, instance.instance_field); + instance.instance_field = Math.E; + assertEquals(Math.E, getInstanceField(instance)); + } + + private static CallSite lookupVirtual( + MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable { + // To get the point-of-use and invokedynamic to work the methodType here has the + // receiver type as the leading paramter which needs to be dropped for findVirtual(). + MethodType mt = methodType.dropParameterTypes(0, 1); + MethodHandle mh = lookup.findVirtual(TestInvocationKinds.class, name, mt); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod(enclosingType = TestInvocationKinds.class, name = "lookupVirtual"), + fieldOrMethodName = "getMaxIntegerValue", + returnType = int.class, + parameterTypes = {TestInvocationKinds.class, int.class, int.class} + ) + private static int maxIntegerValue(TestInvocationKinds receiver, int x, int y) { + assertNotReached(); + return 0; + } + + public int getMaxIntegerValue(int x, int y) { + return x > y ? x : y; + } + + static void testInvokeVirtual() { + System.out.print("testInvokeVirtual => max(77, -3) = "); + TestInvocationKinds receiver = new TestInvocationKinds(); + int result = maxIntegerValue(receiver, 77, -3); + System.out.println(result); + } + + static class Widget { + int value; + public Widget(int value) {} + } + + private static CallSite lookupConstructor( + MethodHandles.Lookup lookup, String name, MethodType methodType) throws Throwable { + // methodType = (constructorParams);classToBeConstructed + Class<?> cls = methodType.returnType(); + MethodType constructorMethodType = methodType.changeReturnType(void.class); + MethodHandle mh = lookup.findConstructor(cls, constructorMethodType); + return new ConstantCallSite(mh); + } + + @CalledByIndy( + bootstrapMethod = + @BootstrapMethod( + enclosingType = TestInvocationKinds.class, + name = "lookupConstructor" + ), + fieldOrMethodName = "unused", + returnType = Widget.class, + parameterTypes = {int.class} + ) + private static Widget makeWidget(int v) { + assertNotReached(); + return null; + } + + static void testConstructor() { + System.out.print("testConstructor => "); + Widget receiver = makeWidget(3); + assertEquals(Widget.class, receiver.getClass()); + System.out.println(receiver.getClass()); + } + + public static void test() { + System.out.println(TestInvocationKinds.class.getName()); + testStaticFieldAccessors(); + testInstanceFieldAccessors(); + testInvokeVirtual(); + testConstructor(); + } +} diff --git a/test/952-invoke-custom/src/TestInvokeCustomWithConcurrentThreads.java b/test/952-invoke-custom/src/TestInvokeCustomWithConcurrentThreads.java index 761d1820db..2ef7ff7e70 100644 --- a/test/952-invoke-custom/src/TestInvokeCustomWithConcurrentThreads.java +++ b/test/952-invoke-custom/src/TestInvokeCustomWithConcurrentThreads.java @@ -14,9 +14,8 @@ * limitations under the License. */ +import annotations.BootstrapMethod; import annotations.CalledByIndy; -import annotations.LinkerMethodHandle; -import annotations.MethodHandleKind; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; @@ -66,16 +65,15 @@ public class TestInvokeCustomWithConcurrentThreads extends TestBase implements R } @CalledByIndy( - invokeMethodHandle = - @LinkerMethodHandle( - kind = MethodHandleKind.INVOKE_STATIC, + bootstrapMethod = + @BootstrapMethod( enclosingType = TestInvokeCustomWithConcurrentThreads.class, name = "linkerMethod", - argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class} + parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class} ), - name = "setCalled", + fieldOrMethodName = "setCalled", returnType = int.class, - argumentTypes = {int.class} + parameterTypes = {int.class} ) private static int setCalled(int index) { called[index].getAndIncrement(); diff --git a/test/952-invoke-custom/src/TestLinkerMethodMinimalArguments.java b/test/952-invoke-custom/src/TestLinkerMethodMinimalArguments.java index 74ac3cd15e..ff598bb24f 100644 --- a/test/952-invoke-custom/src/TestLinkerMethodMinimalArguments.java +++ b/test/952-invoke-custom/src/TestLinkerMethodMinimalArguments.java @@ -14,9 +14,8 @@ * limitations under the License. */ +import annotations.BootstrapMethod; import annotations.CalledByIndy; -import annotations.LinkerMethodHandle; -import annotations.MethodHandleKind; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; @@ -32,16 +31,15 @@ public class TestLinkerMethodMinimalArguments extends TestBase { static final int FAILURE_TYPE_TARGET_METHOD_THROWS = 3; @CalledByIndy( - invokeMethodHandle = - @LinkerMethodHandle( - kind = MethodHandleKind.INVOKE_STATIC, + bootstrapMethod = + @BootstrapMethod( enclosingType = TestLinkerMethodMinimalArguments.class, - argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, + parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, name = "linkerMethod" ), - name = "_add", + fieldOrMethodName = "_add", returnType = int.class, - argumentTypes = {int.class, int.class} + parameterTypes = {int.class, int.class} ) private static int add(int a, int b) { assertNotReached(); diff --git a/test/952-invoke-custom/src/TestLinkerMethodMultipleArgumentTypes.java b/test/952-invoke-custom/src/TestLinkerMethodMultipleArgumentTypes.java index acb698675f..0015c00844 100644 --- a/test/952-invoke-custom/src/TestLinkerMethodMultipleArgumentTypes.java +++ b/test/952-invoke-custom/src/TestLinkerMethodMultipleArgumentTypes.java @@ -14,10 +14,9 @@ * limitations under the License. */ +import annotations.BootstrapMethod; import annotations.CalledByIndy; import annotations.Constant; -import annotations.LinkerMethodHandle; -import annotations.MethodHandleKind; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; @@ -29,12 +28,11 @@ public class TestLinkerMethodMultipleArgumentTypes extends TestBase { private static int bootstrapRunCount = 0; @CalledByIndy( - invokeMethodHandle = - @LinkerMethodHandle( - kind = MethodHandleKind.INVOKE_STATIC, + bootstrapMethod = + @BootstrapMethod( enclosingType = TestLinkerMethodMultipleArgumentTypes.class, name = "linkerMethod", - argumentTypes = { + parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, @@ -50,7 +48,10 @@ public class TestLinkerMethodMultipleArgumentTypes extends TestBase { long.class } ), - methodHandleExtraArgs = { + fieldOrMethodName = "_add", + returnType = int.class, + parameterTypes = {int.class, int.class}, + constantArgumentsForBootstrapMethod = { @Constant(intValue = -1), @Constant(intValue = 1), @Constant(intValue = (int) 'a'), @@ -61,10 +62,7 @@ public class TestLinkerMethodMultipleArgumentTypes extends TestBase { @Constant(stringValue = "Hello"), @Constant(classValue = TestLinkerMethodMultipleArgumentTypes.class), @Constant(longValue = 123456789L) - }, - name = "_add", - returnType = int.class, - argumentTypes = {int.class, int.class} + } ) private static int add(int a, int b) { assertNotReached(); diff --git a/test/952-invoke-custom/src/TestLinkerUnrelatedBSM.java b/test/952-invoke-custom/src/TestLinkerUnrelatedBSM.java index 3a63b332b6..139a1720f4 100644 --- a/test/952-invoke-custom/src/TestLinkerUnrelatedBSM.java +++ b/test/952-invoke-custom/src/TestLinkerUnrelatedBSM.java @@ -14,20 +14,18 @@ * limitations under the License. */ +import annotations.BootstrapMethod; import annotations.CalledByIndy; import annotations.Constant; -import annotations.LinkerMethodHandle; -import annotations.MethodHandleKind; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; class TestLinkerUnrelatedBSM extends TestBase { @CalledByIndy( - invokeMethodHandle = - @LinkerMethodHandle( - kind = MethodHandleKind.INVOKE_STATIC, + bootstrapMethod = + @BootstrapMethod( enclosingType = UnrelatedBSM.class, - argumentTypes = { + parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, @@ -35,10 +33,10 @@ class TestLinkerUnrelatedBSM extends TestBase { }, name = "bsm" ), - methodHandleExtraArgs = {@Constant(classValue = TestLinkerUnrelatedBSM.class)}, - name = "_addf", + fieldOrMethodName = "_addf", returnType = float.class, - argumentTypes = {float.class, float.class} + parameterTypes = {float.class, float.class}, + constantArgumentsForBootstrapMethod = {@Constant(classValue = TestLinkerUnrelatedBSM.class)} ) private static float addf(float a, float b) { assertNotReached(); @@ -50,11 +48,10 @@ class TestLinkerUnrelatedBSM extends TestBase { } @CalledByIndy( - invokeMethodHandle = - @LinkerMethodHandle( - kind = MethodHandleKind.INVOKE_STATIC, + bootstrapMethod = + @BootstrapMethod( enclosingType = UnrelatedBSM.class, - argumentTypes = { + parameterTypes = { MethodHandles.Lookup.class, String.class, MethodType.class, @@ -62,10 +59,10 @@ class TestLinkerUnrelatedBSM extends TestBase { }, name = "bsm" ), - methodHandleExtraArgs = {@Constant(classValue = TestLinkerUnrelatedBSM.class)}, - name = "_subf", + fieldOrMethodName = "_subf", returnType = float.class, - argumentTypes = {float.class, float.class} + parameterTypes = {float.class, float.class}, + constantArgumentsForBootstrapMethod = {@Constant(classValue = TestLinkerUnrelatedBSM.class)} ) private static float subf(float a, float b) { assertNotReached(); diff --git a/test/952-invoke-custom/src/annotations/LinkerMethodHandle.java b/test/952-invoke-custom/src/annotations/BootstrapMethod.java index e0e56c578d..c16783007f 100644 --- a/test/952-invoke-custom/src/annotations/LinkerMethodHandle.java +++ b/test/952-invoke-custom/src/annotations/BootstrapMethod.java @@ -21,18 +21,25 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; -/** Describe a linker method to a method. */ +/** + * Describes a bootstrap method that performs method handle resolution on behalf of an + * invoke-dynamic instruction. + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) -public @interface LinkerMethodHandle { - MethodHandleKind kind(); - +public @interface BootstrapMethod { + /** The class containing the bootstrap method. */ Class<?> enclosingType(); + /** The bootstrap method name. */ String name(); + /** The return type of the bootstrap method. */ Class<?> returnType() default CallSite.class; - Class<?>[] argumentTypes() default {}; + /** The parameter types of the bootstrap method. */ + Class<?>[] parameterTypes() default {Lookup.class, String.class, MethodType.class}; } diff --git a/test/952-invoke-custom/src/annotations/CalledByIndy.java b/test/952-invoke-custom/src/annotations/CalledByIndy.java index 17b8259af4..c4d13a2af4 100644 --- a/test/952-invoke-custom/src/annotations/CalledByIndy.java +++ b/test/952-invoke-custom/src/annotations/CalledByIndy.java @@ -28,15 +28,17 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CalledByIndy { - LinkerMethodHandle[] invokeMethodHandle() default {}; + /** Resolver metadata for bootstrapping */ + BootstrapMethod[] bootstrapMethod() default {}; - LinkerFieldHandle[] fieldMethodHandle() default {}; - - String name(); + /** Field or method name. */ + String fieldOrMethodName(); + /** Return type of method() or field getter() */ Class<?> returnType() default void.class; - Class<?>[] argumentTypes() default {}; + /** Types of parameters for method or field setter() */ + Class<?>[] parameterTypes() default {}; - Constant[] methodHandleExtraArgs() default {}; + Constant[] constantArgumentsForBootstrapMethod() default {}; } diff --git a/test/952-invoke-custom/src/annotations/LinkerFieldHandle.java b/test/952-invoke-custom/src/annotations/LinkerFieldHandle.java deleted file mode 100644 index a3efe24107..0000000000 --- a/test/952-invoke-custom/src/annotations/LinkerFieldHandle.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -package annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.invoke.CallSite; - -/** Describe a linker method to a field. */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.ANNOTATION_TYPE) -public @interface LinkerFieldHandle { - MethodHandleKind kind(); - - Class<?> enclosingType(); - - String name(); - - Class<?> type() default CallSite.class; -} diff --git a/test/952-invoke-custom/src/annotations/MethodHandleKind.java b/test/952-invoke-custom/src/annotations/MethodHandleKind.java deleted file mode 100644 index 5847e2f39f..0000000000 --- a/test/952-invoke-custom/src/annotations/MethodHandleKind.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -package annotations; - -/** MethodHandle invocations kinds supported by invokedynamic */ -public enum MethodHandleKind { - GET_FIELD, - GET_STATIC, - PUT_FIELD, - PUT_STATIC, - INVOKE_VIRTUAL, - INVOKE_STATIC, - INVOKE_SPECIAL, - INVOKE_CONSTRUCTOR, - INVOKE_INTERFACE -} diff --git a/test/952-invoke-custom/src/transformer/IndyTransformer.java b/test/952-invoke-custom/src/transformer/IndyTransformer.java index 286c09859d..45cb4760c9 100644 --- a/test/952-invoke-custom/src/transformer/IndyTransformer.java +++ b/test/952-invoke-custom/src/transformer/IndyTransformer.java @@ -15,11 +15,9 @@ */ package transformer; +import annotations.BootstrapMethod; import annotations.CalledByIndy; import annotations.Constant; -import annotations.LinkerFieldHandle; -import annotations.LinkerMethodHandle; -import annotations.MethodHandleKind; import java.io.InputStream; import java.io.OutputStream; import java.lang.invoke.MethodType; @@ -43,18 +41,17 @@ import org.objectweb.asm.Type; /** * Class for inserting invoke-dynamic instructions in annotated Java class files. * - * This class replaces static method invocations of annotated methods - * with invoke-dynamic instructions. Suppose a method is annotated as: + * <p>This class replaces static method invocations of annotated methods with invoke-dynamic + * instructions. Suppose a method is annotated as: <code> * * @CalledByIndy( - * invokeMethodHandle = - * @LinkerMethodHandle( - * kind = MethodHandleKind.INVOKE_STATIC, - * enclosingType = TestLinkerMethodMinimalArguments.class, - * argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, - * name = "linkerMethod" - * ), - * name = "magicAdd", + * bootstrapMethod = + * @BootstrapMethod( + * enclosingType = TestLinkerMethodMinimalArguments.class, + * parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}, + * name = "linkerMethod" + * ), + * fieldOdMethodName = "magicAdd", * returnType = int.class, * argumentTypes = {int.class, int.class} * ) @@ -66,13 +63,11 @@ import org.objectweb.asm.Type; * return x + y; * } * - * Then invokestatic bytecodes targeting the add() method will be - * replaced invokedynamic instructions targetting the CallSite that is - * construction by the bootstrap method described by the @CalledByIndy - * annotation. + * </code> Then invokestatic bytecodes targeting the add() method will be replaced invokedynamic + * instructions targetting the CallSite that is construction by the bootstrap method described by + * the @CalledByIndy annotation. * - * In the example above, this results in add() being replaced by - * invocations of magicAdd(). + * <p>In the example above, this results in add() being replaced by invocations of magicAdd(). */ class IndyTransformer { @@ -101,7 +96,7 @@ class IndyTransformer { if (opcode == org.objectweb.asm.Opcodes.INVOKESTATIC) { CalledByIndy callsite = callsiteMap.get(name); if (callsite != null) { - insertIndy(callsite.name(), desc, callsite); + insertIndy(callsite.fieldOrMethodName(), desc, callsite); return; } } @@ -109,80 +104,26 @@ class IndyTransformer { } private void insertIndy(String name, String desc, CalledByIndy callsite) { - Handle bsm = buildBootstrapMethodHandle(callsite); - Object[] bsmArgs = buildBootstrapArguments(callsite); + Handle bsm = buildBootstrapMethodHandle(callsite.bootstrapMethod()[0]); + Object[] bsmArgs = + buildBootstrapArguments(callsite.constantArgumentsForBootstrapMethod()); mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); } - private Handle buildBootstrapMethodHandle(CalledByIndy callsite) { - MethodHandleKind kind; - if (callsite.fieldMethodHandle().length != 0) { - return buildBootstrapMethodHandleForField(callsite.fieldMethodHandle()[0]); - } else if (callsite.invokeMethodHandle().length != 0) { - return buildBootstrapMethodHandleForMethod( - callsite.invokeMethodHandle()[0]); - } else { - throw new Error("Missing linker method handle in CalledByIndy annotation"); - } - } - - private Handle buildBootstrapMethodHandleForField(LinkerFieldHandle fieldHandle) { - int handleKind; - switch (fieldHandle.kind()) { - case GET_FIELD: - handleKind = Opcodes.H_GETFIELD; - break; - case GET_STATIC: - handleKind = Opcodes.H_GETSTATIC; - break; - case PUT_FIELD: - handleKind = Opcodes.H_PUTFIELD; - break; - case PUT_STATIC: - handleKind = Opcodes.H_PUTSTATIC; - break; - default: - throw new Error("Unknown field invocation kind: " + fieldHandle.kind()); - } - Class<?> resolverClass = fieldHandle.enclosingType(); - String resolverMethod = fieldHandle.name(); - Class<?> resolverReturnType = fieldHandle.type(); - - // TODO: arguments types to invoke resolver with (default + extra args). - throw new Error("WIP"); - } - - private Handle buildBootstrapMethodHandleForMethod( - LinkerMethodHandle methodHandle) { - int handleKind; - switch (methodHandle.kind()) { - case INVOKE_CONSTRUCTOR: - handleKind = Opcodes.H_NEWINVOKESPECIAL; - break; - case INVOKE_INTERFACE: - handleKind = Opcodes.H_INVOKEINTERFACE; - break; - case INVOKE_SPECIAL: - handleKind = Opcodes.H_INVOKESPECIAL; - break; - case INVOKE_STATIC: - handleKind = Opcodes.H_INVOKESTATIC; - break; - case INVOKE_VIRTUAL: - handleKind = Opcodes.H_INVOKEVIRTUAL; - break; - default: - throw new Error( - "Unknown method invocation kind: " + methodHandle.kind()); - } - String className = Type.getInternalName(methodHandle.enclosingType()); - String methodName = methodHandle.name(); + private Handle buildBootstrapMethodHandle(BootstrapMethod bootstrapMethod) { + String className = Type.getInternalName(bootstrapMethod.enclosingType()); + String methodName = bootstrapMethod.name(); String methodType = MethodType.methodType( - methodHandle.returnType(), methodHandle.argumentTypes()) + bootstrapMethod.returnType(), + bootstrapMethod.parameterTypes()) .toMethodDescriptorString(); return new Handle( - handleKind, className, methodName, methodType, false /* itf */); + Opcodes.H_INVOKESTATIC, + className, + methodName, + methodType, + false /* itf */); } private Object decodeConstant(int index, Constant constant) { @@ -211,11 +152,10 @@ class IndyTransformer { } } - private Object[] buildBootstrapArguments(CalledByIndy callsite) { - Constant[] rawArgs = callsite.methodHandleExtraArgs(); - Object[] args = new Object[rawArgs.length]; - for (int i = 0; i < rawArgs.length; ++i) { - args[i] = decodeConstant(i, rawArgs[i]); + private Object[] buildBootstrapArguments(Constant[] bootstrapMethodArguments) { + Object[] args = new Object[bootstrapMethodArguments.length]; + for (int i = 0; i < bootstrapMethodArguments.length; ++i) { + args[i] = decodeConstant(i, bootstrapMethodArguments[i]); } return args; } @@ -237,8 +177,8 @@ class IndyTransformer { if (calledByIndy == null) { continue; } - if (calledByIndy.name() == null) { - throw new Error("CallByIndy annotation does not specify name"); + if (calledByIndy.fieldOrMethodName() == null) { + throw new Error("CallByIndy annotation does not specify a field or method name"); } final int PRIVATE_STATIC = Modifier.STATIC | Modifier.PRIVATE; if ((m.getModifiers() & PRIVATE_STATIC) != PRIVATE_STATIC) { |