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 */ 31 package test.java.lang.invoke.lookup; 32 33 import java.lang.invoke.MethodHandle; 34 import java.lang.invoke.MethodHandles; 35 import java.lang.invoke.MethodType; 36 import jdk.internal.org.objectweb.asm.*; 37 import org.junit.Test; 38 import static jdk.internal.org.objectweb.asm.Opcodes.*; 39 import 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 */ 49 public 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 }