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 }