Mercurial > hg > release > icedtea7-forest-2.1 > jdk
changeset 4830:57f7c7db785f
8006439: Improve MethodHandles coverage
Summary: Fill out caller-sensitive list. Recognize aliases of non-static methods. Remove use of MethodUtil Trampoline.
Reviewed-by: mchung, twisti, jdn, skoivu
author | andrew |
---|---|
date | Thu, 14 Feb 2013 23:23:10 +0000 |
parents | eb7b1c391c31 |
children | 804fa94e3ac9 |
files | src/share/classes/java/lang/invoke/MethodHandleImpl.java src/share/classes/java/lang/invoke/MethodHandleNatives.java src/share/classes/java/lang/invoke/MethodHandles.java |
diffstat | 3 files changed, 64 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java Mon Jan 21 13:34:48 2013 -0800 +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java Thu Feb 14 23:23:10 2013 +0000 @@ -1278,12 +1278,11 @@ static MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { // Do not use this function to inject calls into system classes. - if (hostClass == null) { - hostClass = C_Trampoline; - } else if (hostClass.isArray() || + if (hostClass == null + || (hostClass.isArray() || hostClass.isPrimitive() || hostClass.getName().startsWith("java.") || - hostClass.getName().startsWith("sun.")) { + hostClass.getName().startsWith("sun."))) { throw new InternalError(); // does not happen, and should not anyway } // For simplicity, convert mh to a varargs-like method. @@ -1293,23 +1292,6 @@ return restoreToType(bccInvoker.bindTo(vamh), mh.type()); } - // This class ("Trampoline") is known to be inside a dead-end class loader. - // Inject all doubtful calls into this class. - private static Class<?> C_Trampoline; - static { - Class<?> tramp = null; - try { - final int FRAME_COUNT_ARG = 1; // [0] Reflection [1] Trampoline - java.lang.reflect.Method gcc = sun.reflect.Reflection.class.getMethod("getCallerClass", int.class); - tramp = (Class<?>) sun.reflect.misc.MethodUtil.invoke(gcc, null, new Object[]{ FRAME_COUNT_ARG }); - if (tramp.getClassLoader() == BindCaller.class.getClassLoader()) - throw new RuntimeException(tramp.getName()+" class loader"); - } catch (Throwable ex) { - throw new InternalError(ex.toString()); - } - C_Trampoline = tramp; - } - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java Mon Jan 21 13:34:48 2013 -0800 +++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java Thu Feb 14 23:23:10 2013 +0000 @@ -412,11 +412,14 @@ */ // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive. static boolean isCallerSensitive(MemberName mem) { - assert(mem.isInvocable()); + if (!mem.isInvocable()) return false; // fields are not caller sensitive Class<?> defc = mem.getDeclaringClass(); switch (mem.getName()) { case "doPrivileged": + case "doPrivilegedWithCombiner": return defc == java.security.AccessController.class; + case "checkMemberAccess": + return canBeCalledVirtual(mem, java.lang.SecurityManager.class); case "getUnsafe": return defc == sun.misc.Unsafe.class; case "lookup": @@ -489,7 +492,7 @@ if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class) return true; break; case "getContextClassLoader": - return defc == java.lang.Thread.class; + return canBeCalledVirtual(mem, java.lang.Thread.class); case "getPackage": case "getPackages": return defc == java.lang.Package.class; @@ -507,6 +510,8 @@ break; case "getCallerClassLoader": return defc == java.lang.ClassLoader.class; + case "registerAsParallelCapable": + return canBeCalledVirtual(mem, java.lang.ClassLoader.class); case "getProxyClass": case "newProxyInstance": return defc == java.lang.reflect.Proxy.class; @@ -518,4 +523,11 @@ } return false; } + static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) { + Class<?> symbolicRefClass = symbolicRef.getDeclaringClass(); + if (symbolicRefClass == definingClass) return true; + if (symbolicRef.isStatic() || symbolicRef.isPrivate()) return false; + return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef + symbolicRefClass.isInterface()); // Mdef implements Msym + } }
--- a/src/share/classes/java/lang/invoke/MethodHandles.java Mon Jan 21 13:34:48 2013 -0800 +++ b/src/share/classes/java/lang/invoke/MethodHandles.java Thu Feb 14 23:23:10 2013 +0000 @@ -584,19 +584,20 @@ MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, true); checkSecurityManager(refc, method); // stack walk magic: do not refactor - return accessStatic(refc, method); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + return accessStatic(refc, method, callerClass); } private - MethodHandle accessStatic(Class<?> refc, MemberName method) throws IllegalAccessException { + MethodHandle accessStatic(Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException { checkMethod(refc, method, true); MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull()); - mh = maybeBindCaller(method, mh); + mh = maybeBindCaller(method, mh, callerClass); return mh; } private MethodHandle resolveStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, true); - return accessStatic(refc, method); + return accessStatic(refc, method, lookupClass); } /** @@ -640,16 +641,17 @@ public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, false); checkSecurityManager(refc, method); // stack walk magic: do not refactor - return accessVirtual(refc, method); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + return accessVirtual(refc, method, callerClass); } private MethodHandle resolveVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, false); - return accessVirtual(refc, method); + return accessVirtual(refc, method, lookupClass); } - private MethodHandle accessVirtual(Class<?> refc, MemberName method) throws IllegalAccessException { + private MethodHandle accessVirtual(Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException { checkMethod(refc, method, false); MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); - mh = maybeBindCaller(method, mh); + mh = maybeBindCaller(method, mh, callerClass); return restrictProtectedReceiver(method, mh); } @@ -753,20 +755,22 @@ checkSpecialCaller(specialCaller); MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); checkSecurityManager(refc, method); // stack walk magic: do not refactor - return accessSpecial(refc, method, specialCaller); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + return accessSpecial(refc, method, callerClass, specialCaller); } private MethodHandle accessSpecial(Class<?> refc, MemberName method, + Class<?> callerClass, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { checkMethod(refc, method, false); MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller); - mh = maybeBindCaller(method, mh); + mh = maybeBindCaller(method, mh, callerClass); return restrictReceiver(method, mh, specialCaller); } private MethodHandle resolveSpecial(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class<?> specialCaller = lookupClass(); checkSpecialCaller(specialCaller); MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); - return accessSpecial(refc, method, specialCaller); + return accessSpecial(refc, method, lookupClass, specialCaller); } /** @@ -927,7 +931,8 @@ checkSecurityManager(refc, method); // stack walk magic: do not refactor checkMethod(refc, method, false); MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); - MethodHandle bcmh = maybeBindCaller(method, dmh); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + MethodHandle bcmh = maybeBindCaller(method, dmh, callerClass); if (bcmh != dmh) return fixVarargs(bcmh.bindTo(receiver), dmh); MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver); if (bmh == null) @@ -961,7 +966,8 @@ assert(method.isMethod()); if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); - mh = maybeBindCaller(method, mh); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + mh = maybeBindCaller(method, mh, callerClass); if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh); return mh; } @@ -994,7 +1000,8 @@ // ignore m.isAccessible: this is a new kind of access checkMethod(m.getDeclaringClass(), method, false); MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull()); - mh = maybeBindCaller(method, mh); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + mh = maybeBindCaller(method, mh, callerClass); return restrictReceiver(method, mh, specialCaller); } @@ -1099,7 +1106,29 @@ } /** + * Find my trustable caller class if m is a caller sensitive method. + * If this lookup object has private access, then the caller class is the lookupClass. + * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). + * This is the same caller class as is used by checkSecurityManager. + * This function performs stack walk magic: do not refactor it. + */ + Class<?> findBoundCallerClass(MemberName m) { + Class<?> callerClass = null; + if (MethodHandleNatives.isCallerSensitive(m)) { + // Do not refactor this to a more "logical" place, since it is stack walk magic. + // Note that this is the same expression as in Step 2 below in checkSecurityManager. + callerClass = ((allowedModes & PRIVATE) != 0 + ? lookupClass // for strong access modes, no extra check + // next line does stack walk magic; do not refactor: + : getCallerClassAtEntryPoint(true)); + } + return callerClass; + } + /** * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>. + * Determines a trustable caller class to compare with refc, the symbolic reference class. + * If this lookup object has private access, then the caller class is the lookupClass. + * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). * This function performs stack walk magic: do not refactor it. */ void checkSecurityManager(Class<?> refc, MemberName m) { @@ -1236,12 +1265,14 @@ MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, 0); return fixVarargs(narrowMH, mh); } - private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh) throws IllegalAccessException { + private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, + Class<?> callerClass) + throws IllegalAccessException { if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) return mh; Class<?> hostClass = lookupClass; if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup - hostClass = null; + hostClass = callerClass; // callerClass came from a security manager style stack walk MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass); cbmh = fixVarargs(cbmh, mh); // in JDK 7 version, varargs happens earlier and must be repaired return cbmh;