1 /*
  2  * Copyright (c) 2014, 2024, 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 testng test.java.lang.invoke.lookup.SpecialStatic
 29  */
 30 package test.java.lang.invoke.lookup;
 31 
 32 import java.lang.classfile.ClassFile;
 33 import java.lang.constant.ClassDesc;
 34 import java.lang.constant.MethodHandleDesc;
 35 import java.lang.constant.MethodTypeDesc;
 36 import java.lang.invoke.MethodHandle;
 37 import java.lang.invoke.MethodHandles;
 38 import java.lang.invoke.MethodType;
 39 import java.lang.reflect.AccessFlag;
 40 
 41 import org.testng.annotations.*;
 42 
 43 import static java.lang.classfile.ClassFile.ACC_PUBLIC;
 44 import static java.lang.classfile.ClassFile.ACC_STATIC;
 45 import static java.lang.constant.ConstantDescs.*;
 46 import static java.lang.constant.DirectMethodHandleDesc.Kind.SPECIAL;
 47 import static org.testng.Assert.*;
 48 
 49 /**
 50  * Test case:
 51  *   class T1            {        int m() { return 1; }}
 52  *   class T2 extends T1 { static int m() { return 2; }}
 53  *   class T3 extends T2 {        int m() { return 3; }}
 54  *
 55  *   T3::test { invokespecial T1.m() T3 } ==> T1::m
 56  */
 57 public class SpecialStatic {
 58     static class CustomClassLoader extends ClassLoader {
 59         public Class<?> loadClass(String name) throws ClassNotFoundException {
 60             if (findLoadedClass(name) != null) {
 61                 return findLoadedClass(name);
 62             }
 63 
 64             if ("T1".equals(name)) {
 65                 byte[] classFile = dumpT1();
 66                 return defineClass("T1", classFile, 0, classFile.length);
 67             }
 68             if ("T2".equals(name)) {
 69                 byte[] classFile = dumpT2();
 70                 return defineClass("T2", classFile, 0, classFile.length);
 71             }
 72             if ("T3".equals(name)) {
 73                 byte[] classFile = dumpT3();
 74                 return defineClass("T3", classFile, 0, classFile.length);
 75             }
 76 
 77             return super.loadClass(name);
 78         }
 79     }
 80 
 81     private static ClassLoader cl = new CustomClassLoader();
 82     private static Class t1, t3;
 83     private static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int);
 84     private static final MethodTypeDesc MTD_Lookup = MethodTypeDesc.of(CD_MethodHandles_Lookup);
 85     private static final String METHOD_NAME = "m";
 86     private static final ClassDesc CD_T1 = ClassDesc.of("T1");
 87     private static final ClassDesc CD_T2 = ClassDesc.of("T2");
 88     private static final ClassDesc CD_T3 = ClassDesc.of("T3");
 89     static {
 90         try {
 91             t1 = cl.loadClass("T1");
 92             t3 = cl.loadClass("T3");
 93         } catch (ClassNotFoundException e) {
 94             throw new Error(e);
 95         }
 96     }
 97 
 98     public static void main(String[] args) throws Throwable {
 99         SpecialStatic test = new SpecialStatic();
100         test.testConstant();
101         test.testFindSpecial();
102     }
103 
104     @Test
105     public void testConstant() throws Throwable {
106         MethodHandle mh = (MethodHandle)t3.getDeclaredMethod("getMethodHandle").invoke(null);
107         int result = (int)mh.invoke(t3.newInstance());
108         assertEquals(result, 1); // T1.m should be invoked.
109     }
110 
111     @Test
112     public void testFindSpecial() throws Throwable {
113         MethodHandles.Lookup lookup = (MethodHandles.Lookup)t3.getDeclaredMethod("getLookup").invoke(null);
114         MethodHandle mh = lookup.findSpecial(t1, "m", MethodType.methodType(int.class), t3);
115         int result = (int)mh.invoke(t3.newInstance());
116         assertEquals(result, 1); // T1.m should be invoked.
117     }
118 
119     public static byte[] dumpT1() {
120         return ClassFile.of().build(CD_T1, clb -> {
121             clb.withSuperclass(CD_Object);
122             clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
123             clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
124                 cob.aload(0);
125                 cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
126                 cob.return_();
127             });
128             clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC, cob -> {
129                 cob.bipush(1);
130                 cob.ireturn();
131             });
132         });
133     }
134 
135     public static byte[] dumpT2() {
136         return ClassFile.of().build(CD_T2, clb -> {
137             clb.withSuperclass(CD_T1);
138             clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
139             clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
140                 cob.aload(0);
141                 cob.invokespecial(CD_T1, INIT_NAME, MTD_void);
142                 cob.return_();
143             });
144             clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC | ACC_STATIC, cob -> {
145                 cob.bipush(2);
146                 cob.ireturn();
147             });
148         });
149     }
150 
151     public static byte[] dumpT3() {
152         return ClassFile.of().build(CD_T3, clb -> {
153             clb.withSuperclass(CD_T2);
154             clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
155             clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
156                 cob.aload(0);
157                 cob.invokespecial(CD_T2, INIT_NAME, MTD_void);
158                 cob.return_();
159             });
160             clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC, cob -> {
161                 cob.bipush(3);
162                 cob.ireturn();
163             });
164             clb.withMethodBody("getMethodHandle", MethodTypeDesc.of(CD_MethodHandle),
165                     ACC_PUBLIC | ACC_STATIC, cob -> {
166                 cob.loadConstant(MethodHandleDesc.ofMethod(SPECIAL, CD_T1, METHOD_NAME, MTD_int));
167                 cob.areturn();
168             });
169             clb.withMethodBody("getLookup", MTD_Lookup,
170                     ACC_PUBLIC | ACC_STATIC, cob -> {
171                 cob.invokestatic(CD_MethodHandles, "lookup", MTD_Lookup);
172                 cob.areturn();
173             });
174         });
175     }
176 }