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