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 /java/lang/invoke/common
 29  * @enablePreview
 30  * @run testng CondyWithGarbageTest
 31  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWithGarbageTest
 32  */
 33 
 34 
 35 import java.lang.classfile.ClassFile;
 36 import java.lang.classfile.CodeBuilder;
 37 import org.testng.Assert;
 38 import org.testng.annotations.Test;
 39 
 40 import java.lang.constant.*;
 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.classDesc;
 46 
 47 public class CondyWithGarbageTest {
 48     static final MethodHandles.Lookup L = MethodHandles.lookup();
 49 
 50     @Test
 51     public void testString() throws Throwable {
 52         MethodHandle mh = lcdStringBasher();
 53         int l = 0;
 54         for (int i = 0; i < 100000; i++) {
 55             l += +((String) mh.invoke()).length();
 56         }
 57         Assert.assertTrue(l > 0);
 58     }
 59 
 60     public static Object bsmString(MethodHandles.Lookup l,
 61                                    String constantName,
 62                                    Class<?> constantType) {
 63         return new StringBuilder(constantName).toString();
 64     }
 65 
 66     static MethodHandle lcdStringBasher() throws Exception {
 67         ClassDesc cd = classDesc(L.lookupClass(), "$Code$String");
 68         byte[] bytes = ClassFile.of().build(cd, classBuilder -> classBuilder
 69                 .withVersion(55, 0)
 70                 .withSuperclass(ConstantDescs.CD_Object)
 71                 .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, ClassFile.ACC_PUBLIC,
 72                         methodBuilder -> methodBuilder
 73                                 .withCode(codeBuilder -> codeBuilder
 74                                         .aload(0)
 75                                         .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
 76                                                 ConstantDescs.MTD_void, false)
 77                                         .return_()))
 78                 .withMethod("m", MethodTypeDesc.of(ConstantDescs.CD_String),
 79                         ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, methodBuilder -> methodBuilder
 80                                 .withCode(codeBuilder -> {
 81                                             codeBuilder
 82                                                     .new_(classDesc(StringBuilder.class))
 83                                                     .dup()
 84                                                     .invokespecial(classDesc(StringBuilder.class), ConstantDescs.INIT_NAME,
 85                                                             ConstantDescs.MTD_void, false)
 86                                                     .astore(0);
 87 
 88                                             for (int i = 10; i < 100; i++) {
 89                                                 ldcString(codeBuilder, Integer.toString(i));
 90                                                 codeBuilder
 91                                                         .astore(1)
 92                                                         .aload(0)
 93                                                         .aload(1)
 94                                                         .invokevirtual(
 95                                                                 classDesc(StringBuilder.class),
 96                                                                 "append",
 97                                                                 MethodTypeDesc.of(
 98                                                                         classDesc(StringBuilder.class),
 99                                                                         classDesc(String.class)))
100                                                         .pop();
101                                             }
102 
103                                             codeBuilder
104                                                     .aload(0)
105                                                     .invokevirtual(
106                                                             classDesc(StringBuilder.class),
107                                                             "toString",
108                                                             MethodTypeDesc.of(classDesc(String.class)))
109                                                     .areturn();
110                                         }
111                                 )));
112         Class<?> gc = L.defineClass(bytes);
113         return L.findStatic(gc, "m", methodType(String.class));
114     }
115 
116     private static void ldcString(CodeBuilder codeBuilder, String name) {
117         codeBuilder.ldc(DynamicConstantDesc.ofNamed(
118                 MethodHandleDesc.of(
119                         DirectMethodHandleDesc.Kind.STATIC,
120                         classDesc(L.lookupClass()),
121                         "bsmString",
122                         methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString()),
123                 name,
124                 classDesc(String.class)
125         ));
126     }
127 
128 
129     @Test
130     public void testStringArray() throws Throwable {
131         MethodHandle mh = lcdStringArrayBasher();
132         int l = 0;
133         for (int i = 0; i < 100000; i++) {
134             l += +((String) mh.invoke()).length();
135         }
136         Assert.assertTrue(l > 0);
137     }
138 
139     public static Object bsmStringArray(MethodHandles.Lookup l,
140                                         String constantName,
141                                         Class<?> constantType) {
142         return new String[]{new StringBuilder(constantName).toString()};
143     }
144 
145     static MethodHandle lcdStringArrayBasher() throws Exception {
146         ClassDesc cd = classDesc(L.lookupClass(), "$Code$StringArray");
147         byte[] bytes = ClassFile.of().build(cd, classBuilder -> classBuilder
148                 .withVersion(55, 0)
149                 .withSuperclass(ConstantDescs.CD_Object)
150                 .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, ClassFile.ACC_PUBLIC,
151                         methodBuilder -> methodBuilder
152                                 .withCode(codeBuilder -> codeBuilder
153                                         .aload(0)
154                                         .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
155                                                 ConstantDescs.MTD_void, false)
156                                         .return_()))
157                 .withMethod("m", MethodTypeDesc.of(classDesc(String.class)),
158                         ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, methodBuilder -> methodBuilder
159                                 .withCode(codeBuilder -> {
160                                             codeBuilder
161                                                     .new_(classDesc(StringBuilder.class))
162                                                     .dup()
163                                                     .invokespecial(classDesc(StringBuilder.class),
164                                                             ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, false)
165                                                     .astore(0);
166 
167                                             for (int i = 10; i < 100; i++) {
168                                                 ldcStringArray(codeBuilder, Integer.toString(i));
169                                                 codeBuilder
170                                                         .bipush(0)
171                                                         .aaload()
172                                                         .astore(1)
173                                                         .aload(0)
174                                                         .aload(1)
175                                                         .invokevirtual(
176                                                                 classDesc(StringBuilder.class),
177                                                                 "append",
178                                                                 MethodTypeDesc.of(
179                                                                         classDesc(StringBuilder.class),
180                                                                         classDesc(String.class)))
181                                                         .pop();
182                                             }
183 
184                                             codeBuilder
185                                                     .aload(0)
186                                                     .invokevirtual(
187                                                             classDesc(StringBuilder.class),
188                                                             "toString",
189                                                             MethodTypeDesc.of(classDesc(String.class)))
190                                                     .areturn();
191                                         }
192                                 )));
193         Class<?> gc = L.defineClass(bytes);
194         return L.findStatic(gc, "m", methodType(String.class));
195     }
196 
197     static void ldcStringArray(CodeBuilder codeBuilder, String name) {
198         codeBuilder.ldc(DynamicConstantDesc.ofNamed(
199                 MethodHandleDesc.of(
200                         DirectMethodHandleDesc.Kind.STATIC,
201                         classDesc(L.lookupClass()),
202                         "bsmStringArray",
203                         methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString()
204                 ),
205                 name,
206                 classDesc(String[].class)
207         ));
208     }
209 }