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