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 }