1/* 2 * Copyright (c) 2014, 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/* 25 * @test 26 * @bug 8032010 27 * @summary method lookup on an abstract method in a concrete class should be successful 28 * @modules java.base/jdk.internal.org.objectweb.asm 29 * @run main TestConcreteClassWithAbstractMethod 30 */ 31 32import jdk.internal.org.objectweb.asm.ClassWriter; 33import jdk.internal.org.objectweb.asm.MethodVisitor; 34 35import static jdk.internal.org.objectweb.asm.Opcodes.*; 36 37/* 38 * class T1 { public int m() {} } 39 * class T2 { public abstract int m(); } 40 * class T3 { public int m() {} } 41 * 42 * Call site: T3.test() { invokevirtual T2.m() } 43 * T3.m() should be invoked 44 */ 45public class TestConcreteClassWithAbstractMethod { 46 static final String classT1 = "p1.T1"; 47 static final String classT2 = "p1.T2"; 48 static final String classT3 = "p1.T3"; 49 50 static final String callerName = classT3; 51 52 public static void main(String[] args) throws Exception { 53 ClassLoader cl = new ClassLoader() { 54 public Class<?> loadClass(String name) throws ClassNotFoundException { 55 if (findLoadedClass(name) != null) { 56 return findLoadedClass(name); 57 } 58 59 if (classT1.equals(name)) { 60 byte[] classFile = dumpT1(); 61 return defineClass(classT1, classFile, 0, classFile.length); 62 } 63 if (classT2.equals(name)) { 64 byte[] classFile = dumpT2(); 65 return defineClass(classT2, classFile, 0, classFile.length); 66 } 67 if (classT3.equals(name)) { 68 byte[] classFile = dumpT3(); 69 return defineClass(classT3, classFile, 0, classFile.length); 70 } 71 72 return super.loadClass(name); 73 } 74 }; 75 76 cl.loadClass(classT1); 77 cl.loadClass(classT2); 78 cl.loadClass(classT3); 79 80 //cl.loadClass(callerName).getDeclaredMethod("m"); 81 cl.loadClass(callerName).newInstance(); 82 83 int result = (Integer)cl.loadClass(callerName).getDeclaredMethod("test").invoke(null); 84 System.out.println(""+result); 85 } 86 87 public static byte[] dumpT1() { 88 ClassWriter cw = new ClassWriter(0); 89 MethodVisitor mv; 90 91 cw.visit(52, ACC_PUBLIC | ACC_SUPER, "p1/T1", null, "java/lang/Object", null); 92 { 93 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 94 mv.visitCode(); 95 mv.visitVarInsn(ALOAD, 0); 96 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 97 mv.visitInsn(RETURN); 98 mv.visitMaxs(1, 1); 99 mv.visitEnd(); 100 } 101 { 102 mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null); 103 mv.visitCode(); 104 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 105 mv.visitLdcInsn("p1/T1.m()"); 106 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V", false); 107 mv.visitIntInsn(BIPUSH, 3); 108 mv.visitInsn(IRETURN); 109 mv.visitMaxs(2, 1); 110 mv.visitEnd(); 111 } 112 cw.visitEnd(); 113 114 return cw.toByteArray(); 115 } 116 117 public static byte[] dumpT2() { 118 ClassWriter cw = new ClassWriter(0); 119 MethodVisitor mv; 120 121 cw.visit(52, ACC_PUBLIC | ACC_SUPER, "p1/T2", null, "p1/T1", null); 122 { 123 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 124 mv.visitCode(); 125 mv.visitVarInsn(ALOAD, 0); 126 mv.visitMethodInsn(INVOKESPECIAL, "p1/T1", "<init>", "()V", false); 127 mv.visitInsn(RETURN); 128 mv.visitMaxs(1, 1); 129 mv.visitEnd(); 130 } 131 { 132 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null); 133 mv.visitEnd(); 134 } 135 cw.visitEnd(); 136 137 return cw.toByteArray(); 138 } 139 140 public static byte[] dumpT3() { 141 ClassWriter cw = new ClassWriter(0); 142 MethodVisitor mv; 143 144 cw.visit(52, ACC_PUBLIC + ACC_SUPER, "p1/T3", null, "p1/T2", null); 145 146 { 147 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 148 mv.visitCode(); 149 mv.visitVarInsn(ALOAD, 0); 150 mv.visitMethodInsn(INVOKESPECIAL, "p1/T2", "<init>", "()V", false); 151 mv.visitInsn(RETURN); 152 mv.visitMaxs(1, 1); 153 mv.visitEnd(); 154 } 155 { 156 mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null); 157 mv.visitCode(); 158 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 159 mv.visitLdcInsn("p1/T3.m()"); 160 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V", false); 161 mv.visitIntInsn(BIPUSH, 2); 162 mv.visitInsn(IRETURN); 163 mv.visitMaxs(2, 1); 164 mv.visitEnd(); 165 } 166 { 167 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null); 168 mv.visitCode(); 169 mv.visitTypeInsn(NEW, "p1/T3"); 170 mv.visitInsn(DUP); 171 mv.visitMethodInsn(INVOKESPECIAL, "p1/T3", "<init>", "()V", false); 172 mv.visitMethodInsn(INVOKEVIRTUAL, "p1/T2", "m", "()I", false); 173 mv.visitInsn(IRETURN); 174 mv.visitMaxs(3, 2); 175 mv.visitEnd(); 176 } 177 cw.visitEnd(); 178 179 return cw.toByteArray(); 180 } 181} 182