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