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 }