1 /* 2 * Copyright (c) 2015, 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 package org.graalvm.compiler.hotspot.test; 25 26 import static org.graalvm.compiler.test.JLModule.uncheckedAddExports; 27 28 import java.lang.reflect.Method; 29 30 import org.graalvm.compiler.core.test.GraalCompilerTest; 31 import org.graalvm.compiler.debug.DebugContext; 32 import org.graalvm.compiler.graph.Node; 33 import org.graalvm.compiler.nodes.Invoke; 34 import org.graalvm.compiler.nodes.StructuredGraph; 35 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 36 import org.graalvm.compiler.test.JLModule; 37 import org.junit.BeforeClass; 38 import org.junit.Test; 39 import org.objectweb.asm.ClassWriter; 40 import org.objectweb.asm.MethodVisitor; 41 import org.objectweb.asm.Opcodes; 42 43 import jdk.vm.ci.meta.ResolvedJavaMethod; 44 45 public class ConstantPoolSubstitutionsTests extends GraalCompilerTest { 46 47 public ConstantPoolSubstitutionsTests() { 48 exportPackage(JAVA_BASE, "jdk.internal.org.objectweb.asm"); 49 } 50 51 @SuppressWarnings("try") 52 protected StructuredGraph test(final String snippet) { 53 ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet)); 54 DebugContext debug = getDebugContext(); 55 try (DebugContext.Scope s = debug.scope("ConstantPoolSubstitutionsTests", method)) { 56 StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); 57 compile(graph.method(), graph); 58 assertNotInGraph(graph, Invoke.class); 59 debug.dump(DebugContext.BASIC_LEVEL, graph, snippet); 60 return graph; 61 } catch (Throwable e) { 62 throw debug.handle(e); 63 } 64 } 65 66 protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) { 67 for (Node node : graph.getNodes()) { 68 if (clazz.isInstance(node)) { 69 fail(node.toString()); 70 } 71 } 72 return graph; 73 } 74 75 private static Object getConstantPoolForObject() { 76 String miscPackage = Java8OrEarlier ? "sun.misc" : "jdk.internal.misc"; 77 try { 78 Class<?> sharedSecretsClass = Class.forName(miscPackage + ".SharedSecrets"); 79 Class<?> javaLangAccessClass = Class.forName(miscPackage + ".JavaLangAccess"); 80 Object jla = sharedSecretsClass.getDeclaredMethod("getJavaLangAccess").invoke(null); 81 return javaLangAccessClass.getDeclaredMethod("getConstantPool", Class.class).invoke(jla, Object.class); 82 } catch (Exception e) { 83 throw new AssertionError(e); 84 } 85 } 86 87 /** 88 * Get the test methods from the generated class. 89 */ 90 @Override 91 protected Method getMethod(String methodName) { 92 Class<?> cl; 93 try { 94 cl = LOADER.findClass(AsmLoader.NAME); 95 addExports(cl); 96 } catch (ClassNotFoundException e) { 97 throw new AssertionError(e); 98 } 99 return getMethod(cl, methodName); 100 } 101 102 @BeforeClass 103 public static void beforeClass() { 104 addExports(AsmLoader.class); 105 } 106 107 /** 108 * This test uses some API hidden by the JDK9 module system. 109 */ 110 private static void addExports(Class<?> c) { 111 if (!Java8OrEarlier) { 112 Object javaBaseModule = JLModule.fromClass(String.class); 113 Object cModule = JLModule.fromClass(c); 114 uncheckedAddExports(javaBaseModule, "jdk.internal.reflect", cModule); 115 uncheckedAddExports(javaBaseModule, "jdk.internal.misc", cModule); 116 } 117 } 118 119 @Test 120 public void testGetSize() { 121 Object cp = getConstantPoolForObject(); 122 test("getSize", cp); 123 } 124 125 @Test 126 public void testGetIntAt() { 127 test("getIntAt"); 128 } 129 130 @Test 131 public void testGetLongAt() { 132 test("getLongAt"); 133 } 134 135 @Test 136 public void testGetFloatAt() { 137 test("getFloatAt"); 138 } 139 140 @Test 141 public void testGetDoubleAt() { 142 test("getDoubleAt"); 143 } 144 145 private static final String PACKAGE_NAME = ConstantPoolSubstitutionsTests.class.getPackage().getName(); 146 private static final String PACKAGE_NAME_INTERNAL = PACKAGE_NAME.replace('.', '/'); 147 148 private static AsmLoader LOADER = new AsmLoader(ConstantPoolSubstitutionsTests.class.getClassLoader()); 149 150 public static class AsmLoader extends ClassLoader { 151 Class<?> loaded; 152 153 static final String NAME = PACKAGE_NAME + ".ConstantPoolTest"; 154 155 public AsmLoader(ClassLoader parent) { 156 super(parent); 157 } 158 159 @Override 160 protected Class<?> findClass(String name) throws ClassNotFoundException { 161 if (name.equals(NAME)) { 162 if (loaded != null) { 163 return loaded; 164 } 165 byte[] bytes = Gen.generateClass(); 166 return (loaded = defineClass(name, bytes, 0, bytes.length)); 167 } else { 168 return super.findClass(name); 169 } 170 } 171 } 172 173 static class Gen implements Opcodes { 174 // @formatter:off 175 /* 176 static class ConstantPoolTest { 177 public static int getSize(Object o) { 178 ConstantPool cp = (ConstantPool) o; 179 return cp.getSize(); 180 } 181 182 public static int getIntAt(Object o) { 183 ConstantPool cp = (ConstantPool) o; 184 return cp.getIntAt(0); 185 } 186 187 public static long getLongAt(Object o) { 188 ConstantPool cp = (ConstantPool) o; 189 return cp.getLongAt(0); 190 } 191 192 public static float getFloatAt(Object o) { 193 ConstantPool cp = (ConstantPool) o; 194 return cp.getFloatAt(0); 195 } 196 197 public static double getDoubleAt(Object o) { 198 ConstantPool cp = (ConstantPool) o; 199 return cp.getDoubleAt(0); 200 } 201 202 public static String getUTF8At(Object o) { 203 ConstantPool cp = (ConstantPool) o; 204 return cp.getUTF8At(0); 205 } 206 } 207 */ 208 // @formatter:on 209 210 static byte[] generateClass() { 211 212 ClassWriter cw = new ClassWriter(0); 213 MethodVisitor mv; 214 215 cw.visit(52, ACC_SUPER, PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", null, "java/lang/Object", null); 216 cw.visitInnerClass(PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", PACKAGE_NAME_INTERNAL + "/ConstantPoolSubstitutionsTests", "ConstantPoolTest", 217 ACC_STATIC); 218 String constantPool = Java8OrEarlier ? "sun/reflect/ConstantPool" : "jdk/internal/reflect/ConstantPool"; 219 220 mv = cw.visitMethod(0, "<init>", "()V", null, null); 221 mv.visitCode(); 222 mv.visitVarInsn(ALOAD, 0); 223 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 224 mv.visitInsn(RETURN); 225 mv.visitMaxs(1, 1); 226 mv.visitEnd(); 227 228 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getSize", "(Ljava/lang/Object;)I", null, null); 229 mv.visitCode(); 230 mv.visitVarInsn(ALOAD, 0); 231 mv.visitTypeInsn(CHECKCAST, constantPool); 232 mv.visitVarInsn(ASTORE, 1); 233 mv.visitVarInsn(ALOAD, 1); 234 mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getSize", "()I", false); 235 mv.visitInsn(IRETURN); 236 mv.visitMaxs(1, 3); 237 mv.visitEnd(); 238 239 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getIntAt", "(Ljava/lang/Object;)I", null, null); 240 mv.visitCode(); 241 mv.visitVarInsn(ALOAD, 0); 242 mv.visitTypeInsn(CHECKCAST, constantPool); 243 mv.visitVarInsn(ASTORE, 1); 244 mv.visitVarInsn(ALOAD, 1); 245 mv.visitInsn(ICONST_0); 246 mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getIntAt", "(I)I", false); 247 mv.visitInsn(IRETURN); 248 mv.visitMaxs(2, 3); 249 mv.visitEnd(); 250 251 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getLongAt", "(Ljava/lang/Object;)J", null, null); 252 mv.visitCode(); 253 mv.visitVarInsn(ALOAD, 0); 254 mv.visitTypeInsn(CHECKCAST, constantPool); 255 mv.visitVarInsn(ASTORE, 1); 256 mv.visitVarInsn(ALOAD, 1); 257 mv.visitInsn(ICONST_0); 258 mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getLongAt", "(I)J", false); 259 mv.visitInsn(LRETURN); 260 mv.visitMaxs(2, 3); 261 mv.visitEnd(); 262 263 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getFloatAt", "(Ljava/lang/Object;)F", null, null); 264 mv.visitCode(); 265 mv.visitVarInsn(ALOAD, 0); 266 mv.visitTypeInsn(CHECKCAST, constantPool); 267 mv.visitVarInsn(ASTORE, 1); 268 mv.visitVarInsn(ALOAD, 1); 269 mv.visitInsn(ICONST_0); 270 mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getFloatAt", "(I)F", false); 271 mv.visitInsn(FRETURN); 272 mv.visitMaxs(2, 3); 273 mv.visitEnd(); 274 275 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getDoubleAt", "(Ljava/lang/Object;)D", null, null); 276 mv.visitCode(); 277 mv.visitVarInsn(ALOAD, 0); 278 mv.visitTypeInsn(CHECKCAST, constantPool); 279 mv.visitVarInsn(ASTORE, 1); 280 mv.visitVarInsn(ALOAD, 1); 281 mv.visitInsn(ICONST_0); 282 mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getDoubleAt", "(I)D", false); 283 mv.visitInsn(DRETURN); 284 mv.visitMaxs(2, 3); 285 mv.visitEnd(); 286 287 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getUTF8At", "(Ljava/lang/Object;)Ljava/lang/String;", null, null); 288 mv.visitCode(); 289 mv.visitVarInsn(ALOAD, 0); 290 mv.visitTypeInsn(CHECKCAST, constantPool); 291 mv.visitVarInsn(ASTORE, 1); 292 mv.visitVarInsn(ALOAD, 1); 293 mv.visitInsn(ICONST_0); 294 mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getUTF8At", "(I)Ljava/lang/String;", false); 295 mv.visitInsn(ARETURN); 296 mv.visitMaxs(2, 3); 297 mv.visitEnd(); 298 cw.visitEnd(); 299 300 return cw.toByteArray(); 301 } 302 } 303 }