ConstantPoolSubstitutionsTests.java revision 12748:fbb9c8026495
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
24package org.graalvm.compiler.hotspot.test;
25
26import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports;
27import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
28
29import java.lang.reflect.Method;
30
31import org.graalvm.compiler.core.common.util.Util;
32import org.graalvm.compiler.core.test.GraalCompilerTest;
33import org.graalvm.compiler.debug.Debug;
34import org.graalvm.compiler.debug.Debug.Scope;
35import org.graalvm.compiler.graph.Node;
36import org.graalvm.compiler.nodes.Invoke;
37import org.graalvm.compiler.nodes.StructuredGraph;
38import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
39import org.junit.BeforeClass;
40import org.junit.Test;
41
42import org.objectweb.asm.ClassWriter;
43import org.objectweb.asm.MethodVisitor;
44import org.objectweb.asm.Opcodes;
45import jdk.vm.ci.meta.ResolvedJavaMethod;
46
47public 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}
325