1/*
2 * Copyright (c) 2014, 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/* @test
25 * @bug 8032400
26 * @summary JSR292: invokeSpecial: InternalError attempting to lookup a method
27 * @modules java.base/jdk.internal.org.objectweb.asm
28 * @compile -XDignore.symbol.file SpecialStatic.java
29 * @run junit test.java.lang.invoke.lookup.SpecialStatic
30 */
31package test.java.lang.invoke.lookup;
32
33import java.lang.invoke.MethodHandle;
34import java.lang.invoke.MethodHandles;
35import java.lang.invoke.MethodType;
36import jdk.internal.org.objectweb.asm.*;
37import org.junit.Test;
38import static jdk.internal.org.objectweb.asm.Opcodes.*;
39import static org.junit.Assert.*;
40
41/**
42 * Test case:
43 *   class T1            {        int m() { return 1; }}
44 *   class T2 extends T1 { static int m() { return 2; }}
45 *   class T3 extends T2 {        int m() { return 3; }}
46 *
47 *   T3::test { invokespecial T1.m() T3 } ==> T1::m
48 */
49public class SpecialStatic {
50    static class CustomClassLoader extends ClassLoader {
51        public Class<?> loadClass(String name) throws ClassNotFoundException {
52            if (findLoadedClass(name) != null) {
53                return findLoadedClass(name);
54            }
55
56            if ("T1".equals(name)) {
57                byte[] classFile = dumpT1();
58                return defineClass("T1", classFile, 0, classFile.length);
59            }
60            if ("T2".equals(name)) {
61                byte[] classFile = dumpT2();
62                return defineClass("T2", classFile, 0, classFile.length);
63            }
64            if ("T3".equals(name)) {
65                byte[] classFile = dumpT3();
66                return defineClass("T3", classFile, 0, classFile.length);
67            }
68
69            return super.loadClass(name);
70        }
71    }
72
73    private static ClassLoader cl = new CustomClassLoader();
74    private static Class t1, t3;
75    static {
76        try {
77            t1 = cl.loadClass("T1");
78            t3 = cl.loadClass("T3");
79        } catch (ClassNotFoundException e) {
80            throw new Error(e);
81        }
82    }
83
84    public static void main(String[] args) throws Throwable {
85        SpecialStatic test = new SpecialStatic();
86        test.testConstant();
87        test.testFindSpecial();
88    }
89
90    @Test
91    public void testConstant() throws Throwable {
92        MethodHandle mh = (MethodHandle)t3.getDeclaredMethod("getMethodHandle").invoke(null);
93        int result = (int)mh.invoke(t3.newInstance());
94        assertEquals(result, 1); // T1.m should be invoked.
95    }
96
97    @Test
98    public void testFindSpecial() throws Throwable {
99        MethodHandles.Lookup lookup = (MethodHandles.Lookup)t3.getDeclaredMethod("getLookup").invoke(null);
100        MethodHandle mh = lookup.findSpecial(t1, "m", MethodType.methodType(int.class), t3);
101        int result = (int)mh.invoke(t3.newInstance());
102        assertEquals(result, 1); // T1.m should be invoked.
103    }
104
105    public static byte[] dumpT1() {
106        ClassWriter cw = new ClassWriter(0);
107        MethodVisitor mv;
108
109        cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T1", null, "java/lang/Object", null);
110
111        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
112        mv.visitCode();
113        mv.visitVarInsn(ALOAD, 0);
114        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
115        mv.visitInsn(RETURN);
116        mv.visitMaxs(1, 1);
117        mv.visitEnd();
118
119        mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null);
120        mv.visitCode();
121        mv.visitIntInsn(BIPUSH, 1);
122        mv.visitInsn(IRETURN);
123        mv.visitMaxs(1, 1);
124        mv.visitEnd();
125
126        cw.visitEnd();
127        return cw.toByteArray();
128    }
129
130    public static byte[] dumpT2() {
131        ClassWriter cw = new ClassWriter(0);
132        MethodVisitor mv;
133
134        cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T2", null, "T1", null);
135
136        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
137        mv.visitCode();
138        mv.visitVarInsn(ALOAD, 0);
139        mv.visitMethodInsn(INVOKESPECIAL, "T1", "<init>", "()V", false);
140        mv.visitInsn(RETURN);
141        mv.visitMaxs(1, 1);
142        mv.visitEnd();
143
144        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()I", null, null);
145        mv.visitCode();
146        mv.visitIntInsn(BIPUSH, 2);
147        mv.visitInsn(IRETURN);
148        mv.visitMaxs(1, 1);
149        mv.visitEnd();
150
151        cw.visitEnd();
152        return cw.toByteArray();
153    }
154
155    public static byte[] dumpT3() {
156        ClassWriter cw = new ClassWriter(0);
157        MethodVisitor mv;
158
159        cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T3", null, "T2", null);
160
161        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
162        mv.visitCode();
163        mv.visitVarInsn(ALOAD, 0);
164        mv.visitMethodInsn(INVOKESPECIAL, "T2", "<init>", "()V", false);
165        mv.visitInsn(RETURN);
166        mv.visitMaxs(1, 1);
167        mv.visitEnd();
168
169        mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null);
170        mv.visitCode();
171        mv.visitIntInsn(BIPUSH, 3);
172        mv.visitInsn(IRETURN);
173        mv.visitMaxs(1, 1);
174        mv.visitEnd();
175
176        // getMethodHandle
177        mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "getMethodHandle", "()Ljava/lang/invoke/MethodHandle;", null, null);
178        mv.visitCode();
179        mv.visitLdcInsn(new Handle(H_INVOKESPECIAL, "T1", "m", "()I"));
180        mv.visitInsn(ARETURN);
181        mv.visitMaxs(1, 0);
182        mv.visitEnd();
183
184        // getLookup
185        mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "getLookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", null, null);
186        mv.visitCode();
187        mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
188        mv.visitInsn(ARETURN);
189        mv.visitMaxs(1, 0);
190        mv.visitEnd();
191
192        cw.visitEnd();
193        return cw.toByteArray();
194    }
195}
196