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