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