1 /* 2 * Copyright (c) 2005, 2017, 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 sun.reflect.misc.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 static Method[] getPublicMethods(Class<?> cls) { 110 // compatibility for update release 111 if (System.getSecurityManager() == null) { 112 return cls.getMethods(); 113 } 114 Map<Signature, Method> sigs = new HashMap<Signature, Method>(); 115 while (cls != null) { 116 boolean done = getInternalPublicMethods(cls, sigs); 117 if (done) { 118 break; 119 } 120 getInterfaceMethods(cls, sigs); 121 cls = cls.getSuperclass(); 122 } 123 return sigs.values().toArray(new Method[sigs.size()]); 124 } 125 126 /* 127 * Process the immediate interfaces of this class or interface. 128 */ 129 private static void getInterfaceMethods(Class<?> cls, 130 Map<Signature, Method> sigs) { 131 Class<?>[] intfs = cls.getInterfaces(); 132 for (int i=0; i < intfs.length; i++) { 133 Class<?> intf = intfs[i]; 134 boolean done = getInternalPublicMethods(intf, sigs); 135 if (!done) { 136 getInterfaceMethods(intf, sigs); 137 } 138 } 139 } 140 141 /* 142 * 143 * Process the methods in this class or interface 144 */ 145 private static boolean getInternalPublicMethods(Class<?> cls, 146 Map<Signature, Method> sigs) { 147 Method[] methods = null; 148 try { 149 /* 150 * This class or interface is non-public so we 151 * can't use any of it's methods. Go back and 152 * try again with a superclass or superinterface. 153 */ 154 if (!Modifier.isPublic(cls.getModifiers())) { 155 return false; 156 } 157 if (!ReflectUtil.isPackageAccessible(cls)) { 158 return false; 159 } 160 161 methods = cls.getMethods(); 162 } catch (SecurityException se) { 163 return false; 164 } 165 166 /* 167 * Check for inherited methods with non-public 168 * declaring classes. They might override and hide 169 * methods from their superclasses or 170 * superinterfaces. 171 */ 172 boolean done = true; 173 for (int i=0; i < methods.length; i++) { 174 Class<?> dc = methods[i].getDeclaringClass(); 175 if (!Modifier.isPublic(dc.getModifiers())) { 176 done = false; 177 break; 178 } 179 } 180 181 if (done) { 182 /* 183 * We're done. Spray all the methods into 184 * the list and then we're out of here. 185 */ 186 for (int i=0; i < methods.length; i++) { 187 addMethod(sigs, methods[i]); 188 } 189 } else { 190 /* 191 * Simulate cls.getDeclaredMethods() by 192 * stripping away inherited methods. 193 */ 194 for (int i=0; i < methods.length; i++) { 195 Class<?> dc = methods[i].getDeclaringClass(); 196 if (cls.equals(dc)) { 197 addMethod(sigs, methods[i]); 198 } 199 } 200 } 201 return done; 202 } 203 204 private static void addMethod(Map<Signature, Method> sigs, Method method) { 205 Signature signature = new Signature(method); 206 if (!sigs.containsKey(signature)) { 207 sigs.put(signature, method); 208 } else if (!method.getDeclaringClass().isInterface()){ 209 /* 210 * Superclasses beat interfaces. 211 */ 212 Method old = sigs.get(signature); 213 if (old.getDeclaringClass().isInterface()) { 214 sigs.put(signature, method); 215 } 216 } 217 } 218 219 /** 220 * A class that represents the unique elements of a method that will be a 221 * key in the method cache. 222 */ 223 private static class Signature { 224 private final String methodName; 225 private final Class<?>[] argClasses; 226 private final int hashCode; 227 228 Signature(Method m) { 229 this.methodName = m.getName(); 230 this.argClasses = m.getParameterTypes(); 231 this.hashCode = methodName.hashCode() + Arrays.hashCode(argClasses); 232 } 233 234 @Override public int hashCode() { 235 return hashCode; 236 } 237 238 @Override public boolean equals(Object o2) { 239 if (this == o2) { 240 return true; 241 } 242 Signature that = (Signature)o2; 243 if (!(methodName.equals(that.methodName))) { 244 return false; 245 } 246 if (argClasses.length != that.argClasses.length) { 247 return false; 248 } 249 for (int i = 0; i < argClasses.length; i++) { 250 if (!(argClasses[i] == that.argClasses[i])) { 251 return false; 252 } 253 } 254 return true; 255 } 256 } 257 258 259 /* 260 * Get the (unnamed) module of the trampoline class 261 */ 262 public static Module getTrampolineModule() { 263 return bounce.getDeclaringClass().getModule(); 264 } 265 266 /* 267 * Bounce through the trampoline. 268 */ 269 public static Object invoke(Method m, Object obj, Object[] params) 270 throws InvocationTargetException, IllegalAccessException { 271 try { 272 return bounce.invoke(null, new Object[] {m, obj, params}); 273 } catch (InvocationTargetException ie) { 274 Throwable t = ie.getCause(); 275 276 if (t instanceof InvocationTargetException) { 277 throw (InvocationTargetException)t; 278 } else if (t instanceof IllegalAccessException) { 279 throw (IllegalAccessException)t; 280 } else if (t instanceof RuntimeException) { 281 throw (RuntimeException)t; 282 } else if (t instanceof Error) { 283 throw (Error)t; 284 } else { 285 throw new Error("Unexpected invocation error", t); 286 } 287 } catch (IllegalAccessException iae) { 288 // this can't happen 289 throw new Error("Unexpected invocation error", iae); 290 } 291 } 292 293 private static Method getTrampoline() { 294 try { 295 return AccessController.doPrivileged( 296 new PrivilegedExceptionAction<Method>() { 297 public Method run() throws Exception { 298 Class<?> t = getTrampolineClass(); 299 Class<?>[] types = { 300 Method.class, Object.class, Object[].class 301 }; 302 Method b = t.getDeclaredMethod("invoke", types); 303 b.setAccessible(true); 304 return b; 305 } 306 }); 307 } catch (Exception e) { 308 throw new InternalError("bouncer cannot be found", e); 309 } 310 } 311 312 313 protected synchronized Class<?> loadClass(String name, boolean resolve) 314 throws ClassNotFoundException 315 { 316 // First, check if the class has already been loaded 317 ReflectUtil.checkPackageAccess(name); 318 Class<?> c = findLoadedClass(name); 319 if (c == null) { 320 try { 321 c = findClass(name); 322 } catch (ClassNotFoundException e) { 323 // Fall through ... 324 } 325 if (c == null) { 326 c = getParent().loadClass(name); 327 } 328 } 329 if (resolve) { 330 resolveClass(c); 331 } 332 return c; 333 } 334 335 336 protected Class<?> findClass(final String name) 337 throws ClassNotFoundException 338 { 339 if (!name.startsWith(MISC_PKG)) { 340 throw new ClassNotFoundException(name); 341 } 342 String path = name.replace('.', '/').concat(".class"); 343 try { 344 InputStream in = MethodUtil.class.getModule().getResourceAsStream(path); 345 if (in != null) { 346 try (in) { 347 byte[] b = in.readAllBytes(); 348 return defineClass(name, b); 349 } 350 } 351 } catch (IOException e) { 352 throw new ClassNotFoundException(name, e); 353 } 354 355 throw new ClassNotFoundException(name); 356 } 357 358 359 /* 360 * Define the proxy classes 361 */ 362 private Class<?> defineClass(String name, byte[] b) throws IOException { 363 CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null); 364 if (!name.equals(TRAMPOLINE)) { 365 throw new IOException("MethodUtil: bad name " + name); 366 } 367 return defineClass(name, b, 0, b.length, cs); 368 } 369 370 protected PermissionCollection getPermissions(CodeSource codesource) 371 { 372 PermissionCollection perms = super.getPermissions(codesource); 373 perms.add(new AllPermission()); 374 return perms; 375 } 376 377 private static Class<?> getTrampolineClass() { 378 try { 379 return Class.forName(TRAMPOLINE, true, new MethodUtil()); 380 } catch (ClassNotFoundException e) { 381 } 382 return null; 383 } 384 385 }