1 /*
2  * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 6991980
27  * @summary  polymorphic signature calls don't share the same CP entries
28  * @modules jdk.jdeps/com.sun.tools.classfile
29  * @run main TestCP
30  */
31 
32 import com.sun.tools.classfile.Instruction;
33 import com.sun.tools.classfile.Attribute;
34 import com.sun.tools.classfile.ClassFile;
35 import com.sun.tools.classfile.Code_attribute;
36 import com.sun.tools.classfile.ConstantPool.*;
37 import com.sun.tools.classfile.Method;
38 
39 import java.lang.invoke.*;
40 import java.io.*;
41 
42 public class TestCP {
43 
44     static class TestMethodHandleInvokeExact {
45         static final String PS_TYPE = "(Ljava/lang/String;IC)Ljava/lang/Number;";
46 
test(MethodHandle mh)47         void test(MethodHandle mh) throws Throwable {
48             Number n = (Number)mh.invokeExact("daddy",1,'n');
49             n = (Number)mh.invokeExact("bunny",1,'d');
50             n = (Number)(mh.invokeExact("foo",1,'d'));
51             n = (Number)((mh.invokeExact("bar",1,'d')));
52         }
53     }
54 
55     static class TestVarHandleGet {
56         static final String PS_TYPE = "(Ljava/lang/String;IC)Ljava/lang/Number;";
57 
58         // Test with sig-poly return type
test(VarHandle vh)59         void test(VarHandle vh) throws Throwable {
60             Number n = (Number)vh.get("daddy",1,'n');
61             n = (Number)vh.get("bunny",1,'d');
62             n = (Number)(vh.get("foo",1,'d'));
63             n = (Number)((vh.get("bar",1,'d')));
64         }
65     }
66 
67     static class TestVarHandleSet {
68         static final String PS_TYPE = "(Ljava/lang/String;IC)V";
69 
70         // Test with non-sig-poly void return type
test(VarHandle vh)71         void test(VarHandle vh) throws Throwable {
72             vh.set("daddy",1,'n');
73             vh.set("bunny",1,'d');
74             vh.set("foo",1,'d');
75             vh.set("bar",1,'d');
76         }
77     }
78 
79     static class TestVarHandleCompareAndSet {
80         static final String PS_TYPE = "(Ljava/lang/String;IC)Z";
81 
82         // Test with non-sig-poly boolean return type
test(VarHandle vh)83         void test(VarHandle vh) throws Throwable {
84             boolean r = vh.compareAndSet("daddy",1,'n');
85             r = vh.compareAndSet("bunny",1,'d');
86             r = (vh.compareAndSet("foo",1,'d'));
87             r = ((vh.compareAndSet("bar",1,'d')));
88         }
89     }
90 
91     static final int PS_CALLS_COUNT = 4;
92     static final String TEST_METHOD_NAME = "test";
93 
main(String... args)94     public static void main(String... args) throws Exception {
95         new TestCP().run();
96     }
97 
run()98     public void run() throws Exception {
99         verifySigPolyInvokeVirtual(
100                 getTestFile(TestMethodHandleInvokeExact.class),
101                 TestMethodHandleInvokeExact.PS_TYPE);
102 
103         verifySigPolyInvokeVirtual(
104                 getTestFile(TestVarHandleGet.class),
105                 TestVarHandleGet.PS_TYPE);
106 
107         verifySigPolyInvokeVirtual(
108                 getTestFile(TestVarHandleSet.class),
109                 TestVarHandleSet.PS_TYPE);
110 
111         verifySigPolyInvokeVirtual(
112                 getTestFile(TestVarHandleCompareAndSet.class),
113                 TestVarHandleCompareAndSet.PS_TYPE);
114     }
115 
getTestFile(Class<?> c)116     static File getTestFile(Class<?> c) {
117         String workDir = System.getProperty("test.classes");
118         return new File(workDir, getTestName(c));
119     }
getTestName(Class<?> c)120     static String getTestName(Class<?> c) {
121         return c.getName() + ".class";
122     }
123 
verifySigPolyInvokeVirtual(File f, String psType)124     void verifySigPolyInvokeVirtual(File f, String psType) {
125         System.err.println("verify: " + f);
126         try {
127             int count = 0;
128             ClassFile cf = ClassFile.read(f);
129             Method testMethod = null;
130             for (Method m : cf.methods) {
131                 if (m.getName(cf.constant_pool).equals(TEST_METHOD_NAME)) {
132                     testMethod = m;
133                     break;
134                 }
135             }
136             if (testMethod == null) {
137                 throw new Error("Test method not found");
138             }
139             Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code);
140             if (testMethod == null) {
141                 throw new Error("Code attribute for test() method not found");
142             }
143             int instr_count = 0;
144             int cp_entry = -1;
145 
146             for (Instruction i : ea.getInstructions()) {
147                 if (i.getMnemonic().equals("invokevirtual")) {
148                     instr_count++;
149                     if (cp_entry == -1) {
150                         cp_entry = i.getUnsignedShort(1);
151                     } else if (cp_entry != i.getUnsignedShort(1)) {
152                         throw new Error("Unexpected CP entry in polymorphic signature call");
153                     }
154                     CONSTANT_Methodref_info methRef =
155                             (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
156                     String type = methRef.getNameAndTypeInfo().getType();
157                     if (!type.equals(psType)) {
158                         throw new Error("Unexpected type in polymorphic signature call: " + type);
159                     }
160                 }
161             }
162             if (instr_count != PS_CALLS_COUNT) {
163                 throw new Error("Wrong number of polymorphic signature call found: " + instr_count);
164             }
165         } catch (Exception e) {
166             e.printStackTrace();
167             throw new Error("error reading " + f +": " + e);
168         }
169     }
170 }
171