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