1 /*
2  * Copyright (c) 2017, 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 8186046
27  * @summary Test for condy BSMs returning primitive values or null
28  * @library /lib/testlibrary/bytecode
29  * @build jdk.experimental.bytecode.BasicClassBuilder
30  * @run testng CondyReturnPrimitiveTest
31  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyReturnPrimitiveTest
32  */
33 
34 import jdk.experimental.bytecode.BasicClassBuilder;
35 import jdk.experimental.bytecode.Flag;
36 import jdk.experimental.bytecode.TypedCodeBuilder;
37 import org.testng.Assert;
38 import org.testng.annotations.BeforeClass;
39 import org.testng.annotations.Test;
40 
41 import java.lang.invoke.MethodHandles;
42 import java.lang.invoke.MethodType;
43 import java.lang.reflect.Method;
44 import java.util.concurrent.atomic.AtomicInteger;
45 
46 @Test
47 public class CondyReturnPrimitiveTest {
48     // Counter for number of BSM calls
49     // Use of an AtomicInteger is not strictly necessary in this test
50     // since the BSM is not be called concurrently, but in general
51     // a BSM can be called concurrently for linking different or the *same*
52     // constant so care should be taken if a BSM operates on shared state
53     static final AtomicInteger callCount = new AtomicInteger();
54     // Generated class with methods containing condy ldc
55     Class<?> gc;
56 
57     // Bootstrap method used to represent primitive values
58     // that cannot be represented directly in the constant pool,
59     // such as byte, and for completeness of testing primitive values
60     // that can be represented directly, such as double or long that
61     // take two slots
intConversion(MethodHandles.Lookup l, String constantName, Class<?> constantType, int value)62     public static Object intConversion(MethodHandles.Lookup l,
63                                        String constantName,
64                                        Class<?> constantType,
65                                        int value) {
66         callCount.getAndIncrement();
67 
68         switch (constantName) {
69             case "B":
70                 return (byte) value;
71             case "C":
72                 return (char) value;
73             case "D":
74                 return (double) value;
75             case "F":
76                 return (float) value;
77             case "I":
78                 return value;
79             case "J":
80                 return (long) value;
81             case "S":
82                 return (short) value;
83             case "Z":
84                 return value > 0;
85             case "nullRef":
86                 return null;
87             case "string":
88                 return "string";
89             case "stringArray":
90                 return new String[]{"string", "string"};
91             default:
92                 throw new UnsupportedOperationException();
93         }
94     }
95 
96     @BeforeClass
generateClass()97     public void generateClass() throws Exception {
98         String genClassName = CondyReturnPrimitiveTest.class.getSimpleName() + "$Code";
99         String bsmClassName = CondyReturnPrimitiveTest.class.getCanonicalName().replace('.', '/');
100         String bsmMethodName = "intConversion";
101         String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class,
102                                                      String.class, Class.class, int.class).toMethodDescriptorString();
103 
104         byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0)
105                 .withSuperclass("java/lang/Object")
106                 .withMethod("<init>", "()V", M ->
107                         M.withFlags(Flag.ACC_PUBLIC)
108                                 .withCode(TypedCodeBuilder::new, C ->
109                                         C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
110                                 ))
111                 .withMethod("B", "()B", M ->
112                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
113                                 .withCode(TypedCodeBuilder::new, C ->
114                                         C.ldc("B", "B", bsmClassName, bsmMethodName, bsmDescriptor,
115                                               S -> S.add(Byte.MAX_VALUE))
116                                                 .ireturn()
117                                 ))
118                 .withMethod("C", "()C", M ->
119                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
120                                 .withCode(TypedCodeBuilder::new, C ->
121                                         C.ldc("C", "C", bsmClassName, bsmMethodName, bsmDescriptor,
122                                               S -> S.add(Character.MAX_VALUE))
123                                                 .ireturn()
124                                 ))
125                 .withMethod("D", "()D", M ->
126                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
127                                 .withCode(TypedCodeBuilder::new, C ->
128                                         C.ldc("D", "D", bsmClassName, bsmMethodName, bsmDescriptor,
129                                               S -> S.add(Integer.MAX_VALUE))
130                                                 .dreturn()
131                                 ))
132                 .withMethod("D_AsType", "()D", M ->
133                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
134                                 .withCode(TypedCodeBuilder::new, C ->
135                                         C.ldc("I", "D", bsmClassName, bsmMethodName, bsmDescriptor,
136                                               S -> S.add(Integer.MAX_VALUE))
137                                                 .dreturn()
138                                 ))
139                 .withMethod("F", "()F", M ->
140                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
141                                 .withCode(TypedCodeBuilder::new, C ->
142                                         C.ldc("F", "F", bsmClassName, bsmMethodName, bsmDescriptor,
143                                               S -> S.add(Integer.MAX_VALUE))
144                                                 .freturn()
145                                 ))
146                 .withMethod("F_AsType", "()F", M ->
147                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
148                                 .withCode(TypedCodeBuilder::new, C ->
149                                         C.ldc("I", "F", bsmClassName, bsmMethodName, bsmDescriptor,
150                                               S -> S.add(Integer.MAX_VALUE))
151                                                 .freturn()
152                                 ))
153                 .withMethod("I", "()I", M ->
154                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
155                                 .withCode(TypedCodeBuilder::new, C ->
156                                         C.ldc("I", "I", bsmClassName, bsmMethodName, bsmDescriptor,
157                                               S -> S.add(Integer.MAX_VALUE))
158                                                 .ireturn()
159                                 ))
160                 .withMethod("J", "()J", M ->
161                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
162                                 .withCode(TypedCodeBuilder::new, C ->
163                                         C.ldc("J", "J", bsmClassName, bsmMethodName, bsmDescriptor,
164                                               S -> S.add(Integer.MAX_VALUE))
165                                                 .lreturn()
166                                 ))
167                 .withMethod("J_AsType", "()J", M ->
168                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
169                                 .withCode(TypedCodeBuilder::new, C ->
170                                         C.ldc("I", "J", bsmClassName, bsmMethodName, bsmDescriptor,
171                                               S -> S.add(Integer.MAX_VALUE))
172                                                 .lreturn()
173                                 ))
174                 .withMethod("S", "()S", M ->
175                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
176                                 .withCode(TypedCodeBuilder::new, C ->
177                                         C.ldc("S", "S", bsmClassName, bsmMethodName, bsmDescriptor,
178                                               S -> S.add(Short.MAX_VALUE))
179                                                 .ireturn()
180                                 ))
181                 .withMethod("Z_F", "()Z", M ->
182                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
183                                 .withCode(TypedCodeBuilder::new, C ->
184                                         C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor,
185                                               S -> S.add(0))
186                                                 .ireturn()
187                                 ))
188                 .withMethod("Z_T", "()Z", M ->
189                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
190                                 .withCode(TypedCodeBuilder::new, C ->
191                                         C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor,
192                                               S -> S.add(1))
193                                                 .ireturn()
194                                 ))
195                 .withMethod("null", "()Ljava/lang/Object;", M ->
196                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
197                                 .withCode(TypedCodeBuilder::new, C ->
198                                         C.ldc("nullRef", "Ljava/lang/Object;", bsmClassName, bsmMethodName, bsmDescriptor,
199                                               S -> S.add(Integer.MAX_VALUE))
200                                                 .areturn()
201                                 ))
202                 .withMethod("string", "()Ljava/lang/String;", M ->
203                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
204                                 .withCode(TypedCodeBuilder::new, C ->
205                                         C.ldc("string", "Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor,
206                                               S -> S.add(Integer.MAX_VALUE))
207                                                 .areturn()
208                                 ))
209                 .withMethod("stringArray", "()[Ljava/lang/String;", M ->
210                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
211                                 .withCode(TypedCodeBuilder::new, C ->
212                                         C.ldc("stringArray", "[Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor,
213                                               S -> S.add(Integer.MAX_VALUE))
214                                                 .areturn()
215                                 ))
216                 .build();
217 
218         gc = MethodHandles.lookup().defineClass(byteArray);
219     }
220 
221     @Test
testPrimitives()222     public void testPrimitives() throws Exception {
223         testConstants();
224         int expectedCallCount = callCount.get();
225 
226         // Ensure when run a second time that the bootstrap method is not
227         // invoked and the constants are cached
228         testConstants();
229         Assert.assertEquals(callCount.get(), expectedCallCount);
230     }
231 
232     @Test
testRefs()233     public void testRefs() throws Exception {
234         testConstant("string", "string");
235         testConstant("stringArray", new String[]{"string", "string"});
236     }
237 
testConstants()238     void testConstants() throws Exception {
239         // Note: for the _asType methods the BSM returns an int which is
240         // then converted by an asType transformation
241 
242         testConstant("B", Byte.MAX_VALUE);
243         testConstant("C", Character.MAX_VALUE);
244         testConstant("D", (double) Integer.MAX_VALUE);
245         testConstant("D_AsType", (double) Integer.MAX_VALUE);
246         testConstant("F", (float) Integer.MAX_VALUE);
247         testConstant("F_AsType", (float) Integer.MAX_VALUE);
248         testConstant("I", Integer.MAX_VALUE);
249         testConstant("J", (long) Integer.MAX_VALUE);
250         testConstant("J_AsType", (long) Integer.MAX_VALUE);
251         testConstant("S", Short.MAX_VALUE);
252         testConstant("Z_F", false);
253         testConstant("Z_T", true);
254         testConstant("null", null);
255     }
256 
testConstant(String name, Object expected)257     void testConstant(String name, Object expected) throws Exception {
258         Method m = gc.getDeclaredMethod(name);
259         Assert.assertEquals(m.invoke(null), expected);
260     }
261 }
262