1 /* 2 * Copyright (c) 2005, 2018, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.reflect; 27 28 import java.io.EOFException; 29 import java.security.AllPermission; 30 import java.security.AccessController; 31 import java.security.PermissionCollection; 32 import java.security.SecureClassLoader; 33 import java.security.PrivilegedExceptionAction; 34 import java.security.CodeSource; 35 import java.io.InputStream; 36 import java.io.BufferedInputStream; 37 import java.io.IOException; 38 import java.net.URL; 39 import java.net.URLConnection; 40 import java.lang.reflect.Method; 41 import java.lang.reflect.InvocationTargetException; 42 import java.lang.reflect.Modifier; 43 import java.util.Arrays; 44 import java.util.HashMap; 45 import java.util.Map; 46 import com.sun.javafx.reflect.ReflectUtil; 47 48 49 class Trampoline { 50 static { 51 if (Trampoline.class.getClassLoader() == null) { 52 throw new Error( 53 "Trampoline must not be defined by the bootstrap classloader"); 54 } 55 if (Trampoline.class.getClassLoader() == ClassLoader.getPlatformClassLoader()) { 56 throw new Error( 57 "Trampoline must not be defined by the platform classloader"); 58 } 59 } 60 61 private static void ensureInvocableMethod(Method m) 62 throws InvocationTargetException 63 { 64 Class<?> clazz = m.getDeclaringClass(); 65 if (clazz.equals(AccessController.class) || 66 clazz.equals(Method.class) || 67 clazz.getName().startsWith("java.lang.invoke.")) 68 throw new InvocationTargetException( 69 new UnsupportedOperationException("invocation not supported")); 70 } 71 72 private static Object invoke(Method m, Object obj, Object[] params) 73 throws InvocationTargetException, IllegalAccessException 74 { 75 ensureInvocableMethod(m); 76 return m.invoke(obj, params); 77 } 78 } 79 80 /* 81 * Create a trampoline class. 82 */ 83 public final class MethodUtil extends SecureClassLoader { 84 private static final String MISC_PKG = "com.sun.javafx.reflect."; 85 private static final String TRAMPOLINE = MISC_PKG + "Trampoline"; 86 private static final Method bounce = getTrampoline(); 87 88 private MethodUtil() { 89 super(); 90 } 91 92 public static Method getMethod(Class<?> cls, String name, Class<?>[] args) 93 throws NoSuchMethodException { 94 ReflectUtil.checkPackageAccess(cls); 95 return cls.getMethod(name, args); 96 } 97 98 public static Method[] getMethods(Class<?> cls) { 99 ReflectUtil.checkPackageAccess(cls); 100 return cls.getMethods(); 101 } 102 103 /* 104 * Discover the public methods on public classes 105 * and interfaces accessible to any caller by calling 106 * Class.getMethods() and walking towards Object until 107 * we're done. 108 */ 109 /*public*/ 110 static Method[] getPublicMethods(Class<?> cls) { 111 // compatibility for update release 112 if (System.getSecurityManager() == null) { 113 return cls.getMethods(); 114 } 115 Map<Signature, Method> sigs = new HashMap<Signature, Method>(); 116 while (cls != null) { 117 boolean done = getInternalPublicMethods(cls, sigs); 118 if (done) { 119 break; 120 } 121 getInterfaceMethods(cls, sigs); 122 cls = cls.getSuperclass(); 123 } 124 return sigs.values().toArray(new Method[sigs.size()]); 125 } 126 127 /* 128 * Process the immediate interfaces of this class or interface. 129 */ 130 private static void getInterfaceMethods(Class<?> cls, 131 Map<Signature, Method> sigs) { 132 Class<?>[] intfs = cls.getInterfaces(); 133 for (int i=0; i < intfs.length; i++) { 134 Class<?> intf = intfs[i]; 135 boolean done = getInternalPublicMethods(intf, sigs); 136 if (!done) { 137 getInterfaceMethods(intf, sigs); 138 } 139 } 140 } 141 142 /* 143 * 144 * Process the methods in this class or interface 145 */ 146 private static boolean getInternalPublicMethods(Class<?> cls, 147 Map<Signature, Method> sigs) { 148 Method[] methods = null; 149 try { 150 /* 151 * This class or interface is non-public so we 152 * can't use any of it's methods. Go back and 153 * try again with a superclass or superinterface. 154 */ 155 if (!Modifier.isPublic(cls.getModifiers())) { 156 return false; 157 } 158 if (!ReflectUtil.isPackageAccessible(cls)) { 159 return false; 160 } 161 162 methods = cls.getMethods(); 163 } catch (SecurityException se) { 164 return false; 165 } 166 167 /* 168 * Check for inherited methods with non-public 169 * declaring classes. They might override and hide 170 * methods from their superclasses or 171 * superinterfaces. 172 */ 173 boolean done = true; 174 for (int i=0; i < methods.length; i++) { 175 Class<?> dc = methods[i].getDeclaringClass(); 176 if (!Modifier.isPublic(dc.getModifiers())) { 177 done = false; 178 break; 179 } 180 } 181 182 if (done) { 183 /* 184 * We're done. Spray all the methods into 185 * the list and then we're out of here. 186 */ 187 for (int i=0; i < methods.length; i++) { 188 addMethod(sigs, methods[i]); 189 } 190 } else { 191 /* 192 * Simulate cls.getDeclaredMethods() by 193 * stripping away inherited methods. 194 */ 195 for (int i=0; i < methods.length; i++) { 196 Class<?> dc = methods[i].getDeclaringClass(); 197 if (cls.equals(dc)) { 198 addMethod(sigs, methods[i]); 199 } 200 } 201 } 202 return done; 203 } 204 205 private static void addMethod(Map<Signature, Method> sigs, Method method) { 206 Signature signature = new Signature(method); 207 if (!sigs.containsKey(signature)) { 208 sigs.put(signature, method); 209 } else if (!method.getDeclaringClass().isInterface()){ 210 /* 211 * Superclasses beat interfaces. 212 */ 213 Method old = sigs.get(signature); 214 if (old.getDeclaringClass().isInterface()) { 215 sigs.put(signature, method); 216 } 217 } 218 } 219 220 /** 221 * A class that represents the unique elements of a method that will be a 222 * key in the method cache. 223 */ 224 private static class Signature { 225 private final String methodName; 226 private final Class<?>[] argClasses; 227 private final int hashCode; 228 229 Signature(Method m) { 230 this.methodName = m.getName(); 231 this.argClasses = m.getParameterTypes(); 232 this.hashCode = methodName.hashCode() + Arrays.hashCode(argClasses); 233 } 234 235 @Override public int hashCode() { 236 return hashCode; 237 } 238 239 @Override public boolean equals(Object o2) { 240 if (this == o2) { 241 return true; 242 } 243 Signature that = (Signature)o2; 244 if (!(methodName.equals(that.methodName))) { 245 return false; 246 } 247 if (argClasses.length != that.argClasses.length) { 248 return false; 249 } 250 for (int i = 0; i < argClasses.length; i++) { 251 if (!(argClasses[i] == that.argClasses[i])) { 252 return false; 253 } 254 } 255 return true; 256 } 257 } 258 259 260 /* 261 * Get the (unnamed) module of the trampoline class 262 */ 263 public static Module getTrampolineModule() { 264 return bounce.getDeclaringClass().getModule(); 265 } 266 267 /* 268 * Bounce through the trampoline. 269 */ 270 public static Object invoke(Method m, Object obj, Object[] params) 271 throws InvocationTargetException, IllegalAccessException { 272 try { 273 return bounce.invoke(null, new Object[] {m, obj, params}); 274 } catch (InvocationTargetException ie) { 275 Throwable t = ie.getCause(); 276 277 if (t instanceof InvocationTargetException) { 278 throw (InvocationTargetException)t; 279 } else if (t instanceof IllegalAccessException) { 280 throw (IllegalAccessException)t; 281 } else if (t instanceof RuntimeException) { 282 throw (RuntimeException)t; 283 } else if (t instanceof Error) { 284 throw (Error)t; 285 } else { 286 throw new Error("Unexpected invocation error", t); 287 } 288 } catch (IllegalAccessException iae) { 289 // this can't happen 290 throw new Error("Unexpected invocation error", iae); 291 } 292 } 293 294 private static Method getTrampoline() { 295 try { 296 return AccessController.doPrivileged( 297 new PrivilegedExceptionAction<Method>() { 298 public Method run() throws Exception { 299 Class<?> t = getTrampolineClass(); 300 Class<?>[] types = { 301 Method.class, Object.class, Object[].class 302 }; 303 Method b = t.getDeclaredMethod("invoke", types); 304 b.setAccessible(true); 305 return b; 306 } 307 }); 308 } catch (Exception e) { 309 throw new InternalError("bouncer cannot be found", e); 310 } 311 } 312 313 314 protected synchronized Class<?> loadClass(String name, boolean resolve) 315 throws ClassNotFoundException 316 { 317 // First, check if the class has already been loaded 318 ReflectUtil.checkPackageAccess(name); 319 Class<?> c = findLoadedClass(name); 320 if (c == null) { 321 try { 322 c = findClass(name); 323 } catch (ClassNotFoundException e) { 324 // Fall through ... 325 } 326 if (c == null) { 327 c = getParent().loadClass(name); 328 } 329 } 330 if (resolve) { 331 resolveClass(c); 332 } 333 return c; 334 } 335 336 337 protected Class<?> findClass(final String name) 338 throws ClassNotFoundException 339 { 340 if (!name.startsWith(MISC_PKG)) { 341 throw new ClassNotFoundException(name); 342 } 343 String path = name.replace('.', '/').concat(".class"); 344 try { 345 InputStream in = MethodUtil.class.getModule().getResourceAsStream(path); 346 if (in != null) { 347 try (in) { 348 byte[] b = in.readAllBytes(); 349 return defineClass(name, b); 350 } 351 } 352 } catch (IOException e) { 353 throw new ClassNotFoundException(name, e); 354 } 355 356 throw new ClassNotFoundException(name); 357 } 358 359 360 /* 361 * Define the proxy classes 362 */ 363 private Class<?> defineClass(String name, byte[] b) throws IOException { 364 CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null); 365 if (!name.equals(TRAMPOLINE)) { 366 throw new IOException("MethodUtil: bad name " + name); 367 } 368 return defineClass(name, b, 0, b.length, cs); 369 } 370 371 protected PermissionCollection getPermissions(CodeSource codesource) 372 { 373 PermissionCollection perms = super.getPermissions(codesource); 374 perms.add(new AllPermission()); 375 return perms; 376 } 377 378 private static Class<?> getTrampolineClass() { 379 try { 380 return Class.forName(TRAMPOLINE, true, new MethodUtil()); 381 } catch (ClassNotFoundException e) { 382 } 383 return null; 384 } 385 386 }