ConstantPoolSubstitutionsTests.java revision 13082:72abda3e08b6
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;
41import org.objectweb.asm.ClassWriter;
42import org.objectweb.asm.MethodVisitor;
43import org.objectweb.asm.Opcodes;
44
45import jdk.vm.ci.meta.ResolvedJavaMethod;
46
47public 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_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    @Test
121    public void testGetSize() {
122        Object cp = getConstantPoolForObject();
123        test("getSize", cp);
124    }
125
126    @Test
127    public void testGetIntAt() {
128        test("getIntAt");
129    }
130
131    @Test
132    public void testGetLongAt() {
133        test("getLongAt");
134    }
135
136    @Test
137    public void testGetFloatAt() {
138        test("getFloatAt");
139    }
140
141    @Test
142    public void testGetDoubleAt() {
143        test("getDoubleAt");
144    }
145
146    private static final String PACKAGE_NAME = ConstantPoolSubstitutionsTests.class.getPackage().getName();
147    private static final String PACKAGE_NAME_INTERNAL = PACKAGE_NAME.replace('.', '/');
148
149    private static AsmLoader LOADER = new AsmLoader(ConstantPoolSubstitutionsTests.class.getClassLoader());
150
151    public static class AsmLoader extends ClassLoader {
152        Class<?> loaded;
153
154        static final String NAME = PACKAGE_NAME + ".ConstantPoolTest";
155
156        public AsmLoader(ClassLoader parent) {
157            super(parent);
158        }
159
160        @Override
161        protected Class<?> findClass(String name) throws ClassNotFoundException {
162            if (name.equals(NAME)) {
163                if (loaded != null) {
164                    return loaded;
165                }
166                byte[] bytes = Gen.generateClass();
167                return (loaded = defineClass(name, bytes, 0, bytes.length));
168            } else {
169                return super.findClass(name);
170            }
171        }
172    }
173
174    static class Gen implements Opcodes {
175        // @formatter:off
176        /*
177        static class ConstantPoolTest {
178            public static int getSize(Object o) {
179                ConstantPool cp = (ConstantPool) o;
180                return cp.getSize();
181            }
182
183            public static int getIntAt(Object o) {
184                ConstantPool cp = (ConstantPool) o;
185                return cp.getIntAt(0);
186            }
187
188            public static long getLongAt(Object o) {
189                ConstantPool cp = (ConstantPool) o;
190                return cp.getLongAt(0);
191            }
192
193            public static float getFloatAt(Object o) {
194                ConstantPool cp = (ConstantPool) o;
195                return cp.getFloatAt(0);
196            }
197
198            public static double getDoubleAt(Object o) {
199                ConstantPool cp = (ConstantPool) o;
200                return cp.getDoubleAt(0);
201            }
202
203            public static String getUTF8At(Object o) {
204                ConstantPool cp = (ConstantPool) o;
205                return cp.getUTF8At(0);
206            }
207        }
208        */
209        // @formatter:on
210
211        static byte[] generateClass() {
212
213            ClassWriter cw = new ClassWriter(0);
214            MethodVisitor mv;
215
216            cw.visit(52, ACC_SUPER, PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", null, "java/lang/Object", null);
217            cw.visitInnerClass(PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", PACKAGE_NAME_INTERNAL + "/ConstantPoolSubstitutionsTests", "ConstantPoolTest",
218                            ACC_STATIC);
219            String constantPool = Java8OrEarlier ? "sun/reflect/ConstantPool" : "jdk/internal/reflect/ConstantPool";
220
221            mv = cw.visitMethod(0, "<init>", "()V", null, null);
222            mv.visitCode();
223            mv.visitVarInsn(ALOAD, 0);
224            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
225            mv.visitInsn(RETURN);
226            mv.visitMaxs(1, 1);
227            mv.visitEnd();
228
229            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getSize", "(Ljava/lang/Object;)I", null, null);
230            mv.visitCode();
231            mv.visitVarInsn(ALOAD, 0);
232            mv.visitTypeInsn(CHECKCAST, constantPool);
233            mv.visitVarInsn(ASTORE, 1);
234            mv.visitVarInsn(ALOAD, 1);
235            mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getSize", "()I", false);
236            mv.visitInsn(IRETURN);
237            mv.visitMaxs(1, 3);
238            mv.visitEnd();
239
240            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getIntAt", "(Ljava/lang/Object;)I", null, null);
241            mv.visitCode();
242            mv.visitVarInsn(ALOAD, 0);
243            mv.visitTypeInsn(CHECKCAST, constantPool);
244            mv.visitVarInsn(ASTORE, 1);
245            mv.visitVarInsn(ALOAD, 1);
246            mv.visitInsn(ICONST_0);
247            mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getIntAt", "(I)I", false);
248            mv.visitInsn(IRETURN);
249            mv.visitMaxs(2, 3);
250            mv.visitEnd();
251
252            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getLongAt", "(Ljava/lang/Object;)J", null, null);
253            mv.visitCode();
254            mv.visitVarInsn(ALOAD, 0);
255            mv.visitTypeInsn(CHECKCAST, constantPool);
256            mv.visitVarInsn(ASTORE, 1);
257            mv.visitVarInsn(ALOAD, 1);
258            mv.visitInsn(ICONST_0);
259            mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getLongAt", "(I)J", false);
260            mv.visitInsn(LRETURN);
261            mv.visitMaxs(2, 3);
262            mv.visitEnd();
263
264            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getFloatAt", "(Ljava/lang/Object;)F", null, null);
265            mv.visitCode();
266            mv.visitVarInsn(ALOAD, 0);
267            mv.visitTypeInsn(CHECKCAST, constantPool);
268            mv.visitVarInsn(ASTORE, 1);
269            mv.visitVarInsn(ALOAD, 1);
270            mv.visitInsn(ICONST_0);
271            mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getFloatAt", "(I)F", false);
272            mv.visitInsn(FRETURN);
273            mv.visitMaxs(2, 3);
274            mv.visitEnd();
275
276            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getDoubleAt", "(Ljava/lang/Object;)D", null, null);
277            mv.visitCode();
278            mv.visitVarInsn(ALOAD, 0);
279            mv.visitTypeInsn(CHECKCAST, constantPool);
280            mv.visitVarInsn(ASTORE, 1);
281            mv.visitVarInsn(ALOAD, 1);
282            mv.visitInsn(ICONST_0);
283            mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getDoubleAt", "(I)D", false);
284            mv.visitInsn(DRETURN);
285            mv.visitMaxs(2, 3);
286            mv.visitEnd();
287
288            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getUTF8At", "(Ljava/lang/Object;)Ljava/lang/String;", null, null);
289            mv.visitCode();
290            mv.visitVarInsn(ALOAD, 0);
291            mv.visitTypeInsn(CHECKCAST, constantPool);
292            mv.visitVarInsn(ASTORE, 1);
293            mv.visitVarInsn(ALOAD, 1);
294            mv.visitInsn(ICONST_0);
295            mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getUTF8At", "(I)Ljava/lang/String;", false);
296            mv.visitInsn(ARETURN);
297            mv.visitMaxs(2, 3);
298            mv.visitEnd();
299            cw.visitEnd();
300
301            return cw.toByteArray();
302        }
303    }
304}
305