1 /*
2  * Copyright (c) 2016, 2019, 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 package jdk.vm.ci.hotspot.test;
25 
26 import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
27 import jdk.vm.ci.meta.JavaConstant;
28 import jdk.vm.ci.meta.MetaAccessProvider;
29 import jdk.vm.ci.meta.MethodHandleAccessProvider;
30 import jdk.vm.ci.runtime.JVMCI;
31 import org.testng.annotations.DataProvider;
32 
33 import java.io.File;
34 import java.lang.invoke.MethodHandle;
35 import java.lang.invoke.MethodHandles;
36 import java.lang.invoke.MethodType;
37 import java.net.MalformedURLException;
38 import java.net.URL;
39 import java.net.URLClassLoader;
40 import java.nio.file.Paths;
41 
42 public class MethodHandleAccessProviderData implements TestInterface {
43     private static final MetaAccessProvider META_ACCESS = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
44     private static final HotSpotConstantReflectionProvider CONSTANT_REFLECTION = (HotSpotConstantReflectionProvider) JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection();
45     // see DirectMethodHandle.java to check invoke* method names assignment
46     private static final String IVIRTUAL_RESOLVED_NAME = "invokeVirtual";
47     private static final String ISTATIC_RESOLVED_NAME = "invokeStatic";
48     private static final String ISPECIAL_RESOLVED_NAME = "invokeSpecial";
49     private static final String ISTATICINIT_RESOLVED_NAME = "invokeStaticInit";
50     private static final String IINTERFACE_RESOLVED_NAME = "invokeInterface";
51     private static final String INEWSPECIAL_RESOLVED_NAME = "newInvokeSpecial";
52 
53     @DataProvider(name = "intrinsicsPositive")
getIntrinsicsDataPositive()54     public static Object[][] getIntrinsicsDataPositive() {
55         Object[][] result;
56         try {
57             result = new Object[][]{
58                             new Object[]{
59                                             META_ACCESS.lookupJavaMethod(MethodHandle.class.getDeclaredMethod("invokeBasic", Object[].class)),
60                                             MethodHandleAccessProvider.IntrinsicMethod.INVOKE_BASIC},
61                             new Object[]{
62                                             META_ACCESS.lookupJavaMethod(MethodHandle.class.getDeclaredMethod("linkToInterface", Object[].class)),
63                                             MethodHandleAccessProvider.IntrinsicMethod.LINK_TO_INTERFACE},
64                             new Object[]{
65                                             META_ACCESS.lookupJavaMethod(MethodHandle.class.getDeclaredMethod("linkToStatic", Object[].class)),
66                                             MethodHandleAccessProvider.IntrinsicMethod.LINK_TO_STATIC},
67                             new Object[]{
68                                             META_ACCESS.lookupJavaMethod(MethodHandle.class.getDeclaredMethod("linkToVirtual", Object[].class)),
69                                             MethodHandleAccessProvider.IntrinsicMethod.LINK_TO_VIRTUAL},
70                             new Object[]{
71                                             META_ACCESS.lookupJavaMethod(MethodHandle.class.getDeclaredMethod("linkToSpecial", Object[].class)),
72                                             MethodHandleAccessProvider.IntrinsicMethod.LINK_TO_SPECIAL}};
73         } catch (NoSuchMethodException e) {
74             throw new Error("TESTBUG: can't find method: " + e, e);
75         }
76         return result;
77     }
78 
79     @DataProvider(name = "intrinsicsNegative")
getIntrinsicsDataNegative()80     public static Object[][] getIntrinsicsDataNegative() {
81         Object[][] result;
82         try {
83             result = new Object[][]{new Object[]{META_ACCESS.lookupJavaMethod(MethodHandle.class.getDeclaredMethod("invokeWithArguments", Object[].class))}};
84         } catch (NoSuchMethodException e) {
85             throw new Error("TESTBUG: can't find method: " + e, e);
86         }
87         return result;
88     }
89 
90     @DataProvider(name = "invokeBasicNegative1")
getInvokeBasicDataNegative1()91     public static Object[][] getInvokeBasicDataNegative1() {
92         Object[][] result;
93         JavaConstant wrongObject = CONSTANT_REFLECTION.forObject("42");
94         // 2nd parameter is force bytecode generation = true/false
95         result = new Object[][]{
96                         new Object[]{wrongObject, true},
97                         new Object[]{wrongObject, false},
98                         new Object[]{JavaConstant.NULL_POINTER, true},
99                         new Object[]{JavaConstant.NULL_POINTER, false}};
100         return result;
101     }
102 
103     @DataProvider(name = "invokeBasicNegative2")
getInvokeBasicDataNegative2()104     public static Object[][] getInvokeBasicDataNegative2() {
105         Object[][] result;
106         // 2nd parameter is force bytecode generation = true/false
107         result = new Object[][]{
108                         new Object[]{null, true},
109                         new Object[]{null, false}};
110         return result;
111     }
112 
113     @DataProvider(name = "invokeBasicPositive")
getInvokeBasicDataPositive()114     public static Object[][] getInvokeBasicDataPositive() {
115         Object[][] result;
116         MethodHandle mhIVirtual;
117         MethodHandle mhIStatic;
118         MethodHandle mhISpecial;
119         MethodHandle mhIStaticInit;
120         MethodHandle mhINewSpecial;
121         MethodHandle mhIInterface;
122         MethodHandles.Lookup lookup = MethodHandles.lookup();
123         MethodType voidRet = MethodType.methodType(void.class);
124         Class<?> self = MethodHandleAccessProviderData.class;
125         // let's get a separate, thus, not initialized class
126         ClassLoader current = self.getClassLoader();
127         String[] cpaths = System.getProperty("java.class.path").split(File.pathSeparator);
128         URL[] urls = new URL[cpaths.length];
129         try {
130             for (int i = 0; i < cpaths.length; i++) {
131                 urls[i] = Paths.get(cpaths[i]).toUri().toURL();
132             }
133         } catch (MalformedURLException e) {
134             throw new Error("Can't parse classpath url: " + e, e);
135         }
136         Class<?> clone;
137         try {
138             clone = new ParentLastURLClassLoader(urls, current).loadClass(self.getName());
139         } catch (ClassNotFoundException e) {
140             throw new Error("TESTBUG: can't find class: " + e, e);
141         }
142         try {
143             mhIVirtual = lookup.findVirtual(self, "publicMethod", voidRet);
144             mhIStatic = lookup.findStatic(self, "staticMethod", voidRet);
145             mhISpecial = lookup.findSpecial(self, "privateMethod", voidRet, self);
146             mhIStaticInit = lookup.findStatic(clone, "staticMethod", voidRet);
147             mhINewSpecial = lookup.findConstructor(self, voidRet);
148             mhIInterface = lookup.findVirtual(TestInterface.class, "interfaceMethod", voidRet);
149         } catch (NoSuchMethodException | IllegalAccessException e) {
150             throw new Error("TESTBUG: lookup failed: " + e, e);
151         }
152         JavaConstant jcIVirtual = CONSTANT_REFLECTION.forObject(mhIVirtual);
153         JavaConstant jcIStatic = CONSTANT_REFLECTION.forObject(mhIStatic);
154         JavaConstant jcISpecial = CONSTANT_REFLECTION.forObject(mhISpecial);
155         JavaConstant jcIStaticInit = CONSTANT_REFLECTION.forObject(mhIStaticInit);
156         JavaConstant jcINewSpecial = CONSTANT_REFLECTION.forObject(mhINewSpecial);
157         JavaConstant jcIInterface = CONSTANT_REFLECTION.forObject(mhIInterface);
158         // 2nd parameter is force bytecode generation = true/false
159         result = new Object[][]{
160                         new Object[]{jcIVirtual, true, IVIRTUAL_RESOLVED_NAME},
161                         new Object[]{jcIVirtual, false, IVIRTUAL_RESOLVED_NAME},
162                         new Object[]{jcIStatic, true, ISTATIC_RESOLVED_NAME},
163                         new Object[]{jcIStatic, false, ISTATIC_RESOLVED_NAME},
164                         new Object[]{jcISpecial, true, ISPECIAL_RESOLVED_NAME},
165                         new Object[]{jcISpecial, false, ISPECIAL_RESOLVED_NAME},
166                         new Object[]{jcIStaticInit, true, ISTATICINIT_RESOLVED_NAME},
167                         new Object[]{jcIStaticInit, false, ISTATICINIT_RESOLVED_NAME},
168                         new Object[]{jcINewSpecial, false, INEWSPECIAL_RESOLVED_NAME},
169                         new Object[]{jcINewSpecial, true, INEWSPECIAL_RESOLVED_NAME},
170                         new Object[]{jcIInterface, false, IINTERFACE_RESOLVED_NAME},
171                         new Object[]{jcIInterface, true, IINTERFACE_RESOLVED_NAME}};
172         return result;
173     }
174 
175     // can't use nested classes for storing these test methods. see JDK-8010319
176     @SuppressWarnings("unused")
privateMethod()177     private void privateMethod() {
178         // empty
179     }
180 
staticMethod()181     public static void staticMethod() {
182         // empty
183     }
184 
publicMethod()185     public void publicMethod() {
186         // empty
187     }
188 
189     @Override
interfaceMethod()190     public void interfaceMethod() {
191         // empty
192     }
193 }
194 
195 interface TestInterface {
interfaceMethod()196     void interfaceMethod();
197 }
198 
199 class ParentLastURLClassLoader extends URLClassLoader {
200 
ParentLastURLClassLoader(URL[] urls, ClassLoader parent)201     ParentLastURLClassLoader(URL[] urls, ClassLoader parent) {
202         super(urls, parent);
203     }
204 
205     @Override
loadClass(String name)206     public Class<?> loadClass(String name) throws ClassNotFoundException {
207         try {
208             Class<?> c = findClass(name);
209             if (c != null) {
210                 return c;
211             }
212         } catch (ClassNotFoundException e) {
213             // ignore
214         }
215         return super.loadClass(name);
216     }
217 }
218