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 Stress test ldc to ensure HotSpot correctly manages oop maps
28  * @library /lib/testlibrary/bytecode /java/lang/invoke/common
29  * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
30  * @run testng CondyWithGarbageTest
31  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWithGarbageTest
32  */
33 
34 
35 import jdk.experimental.bytecode.BasicClassBuilder;
36 import jdk.experimental.bytecode.Flag;
37 import jdk.experimental.bytecode.TypedCodeBuilder;
38 import org.testng.Assert;
39 import org.testng.annotations.Test;
40 
41 import java.lang.invoke.MethodHandle;
42 import java.lang.invoke.MethodHandles;
43 
44 import static java.lang.invoke.MethodType.methodType;
45 import static test.java.lang.invoke.lib.InstructionHelper.cref;
46 import static test.java.lang.invoke.lib.InstructionHelper.csym;
47 
48 public class CondyWithGarbageTest {
49     static final MethodHandles.Lookup L = MethodHandles.lookup();
50 
51     @Test
testString()52     public void testString() throws Throwable {
53         MethodHandle mh = lcdStringBasher();
54         int l = 0;
55         for (int i = 0; i < 100000; i++) {
56             l += +((String) mh.invoke()).length();
57         }
58         Assert.assertTrue(l > 0);
59     }
60 
bsmString(MethodHandles.Lookup l, String constantName, Class<?> constantType)61     public static Object bsmString(MethodHandles.Lookup l,
62                                    String constantName,
63                                    Class<?> constantType) {
64         return new StringBuilder(constantName).toString();
65     }
66 
lcdStringBasher()67     static MethodHandle lcdStringBasher() throws Exception {
68         byte[] byteArray = new BasicClassBuilder(csym(L.lookupClass()) + "$Code$String", 55, 0)
69                 .withSuperclass("java/lang/Object")
70                 .withMethod("<init>", "()V", M ->
71                         M.withFlags(Flag.ACC_PUBLIC)
72                                 .withCode(TypedCodeBuilder::new, C ->
73                                         C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
74                                 ))
75                 .withMethod("m", "()" + cref(String.class), M ->
76                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
77                                 .withCode(TypedCodeBuilder::new, C -> {
78                                               C.new_(csym(StringBuilder.class))
79                                                       .dup()
80                                                       .invokespecial(csym(StringBuilder.class), "<init>", "()V", false)
81                                                       .astore_0();
82 
83                                               for (int i = 10; i < 100; i++) {
84                                                   ldcString(C, Integer.toString(i));
85                                                   C.astore_1().aload_0().aload_1();
86                                                   C.invokevirtual(csym(StringBuilder.class), "append", methodType(StringBuilder.class, String.class).toMethodDescriptorString(), false);
87                                                   C.pop();
88                                               }
89 
90                                               C.aload_0();
91                                               C.invokevirtual(csym(StringBuilder.class), "toString", methodType(String.class).toMethodDescriptorString(), false);
92                                               C.areturn();
93                                           }
94                                 ))
95                 .build();
96 
97         Class<?> gc = L.defineClass(byteArray);
98         return L.findStatic(gc, "m", methodType(String.class));
99     }
100 
ldcString(TypedCodeBuilder<String, String, byte[], ?> C, String name)101     static void ldcString(TypedCodeBuilder<String, String, byte[], ?> C, String name) {
102         C.ldc(name, cref(String.class),
103               csym(L.lookupClass()),
104               "bsmString",
105               methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString(),
106               S -> {
107               });
108     }
109 
110 
111     @Test
testStringArray()112     public void testStringArray() throws Throwable {
113         MethodHandle mh = lcdStringArrayBasher();
114         int l = 0;
115         for (int i = 0; i < 100000; i++) {
116             l += +((String) mh.invoke()).length();
117         }
118         Assert.assertTrue(l > 0);
119     }
120 
bsmStringArray(MethodHandles.Lookup l, String constantName, Class<?> constantType)121     public static Object bsmStringArray(MethodHandles.Lookup l,
122                                         String constantName,
123                                         Class<?> constantType) {
124         return new String[]{new StringBuilder(constantName).toString()};
125     }
126 
lcdStringArrayBasher()127     static MethodHandle lcdStringArrayBasher() throws Exception {
128         byte[] byteArray = new BasicClassBuilder(csym(L.lookupClass()) + "$Code$StringArray", 55, 0)
129                 .withSuperclass("java/lang/Object")
130                 .withMethod("<init>", "()V", M ->
131                         M.withFlags(Flag.ACC_PUBLIC)
132                                 .withCode(TypedCodeBuilder::new, C ->
133                                         C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
134                                 ))
135                 .withMethod("m", "()" + cref(String.class), M ->
136                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
137                                 .withCode(TypedCodeBuilder::new, C -> {
138                                               C.new_(csym(StringBuilder.class))
139                                                       .dup()
140                                                       .invokespecial(csym(StringBuilder.class), "<init>", "()V", false)
141                                                       .astore_0();
142 
143                                               for (int i = 10; i < 100; i++) {
144                                                   ldcStringArray(C, Integer.toString(i));
145                                                   C.bipush(0).aaload().astore_1();
146                                                   C.aload_0().aload_1();
147                                                   C.invokevirtual(csym(StringBuilder.class), "append", methodType(StringBuilder.class, String.class).toMethodDescriptorString(), false);
148                                                   C.pop();
149                                               }
150 
151                                               C.aload_0();
152                                               C.invokevirtual(csym(StringBuilder.class), "toString", methodType(String.class).toMethodDescriptorString(), false);
153                                               C.areturn();
154                                           }
155                                 ))
156                 .build();
157 
158         Class<?> gc = L.defineClass(byteArray);
159         return L.findStatic(gc, "m", methodType(String.class));
160     }
161 
ldcStringArray(TypedCodeBuilder<String, String, byte[], ?> C, String name)162     static void ldcStringArray(TypedCodeBuilder<String, String, byte[], ?> C, String name) {
163         C.ldc(name, cref(String[].class),
164               csym(L.lookupClass()),
165               "bsmStringArray",
166               methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString(),
167               S -> {
168               });
169     }
170 }
171