--- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java Mon Apr 04 19:32:56 2011 +0100
+++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java Mon Apr 04 11:55:05 2011 -0700
@@ -26,6 +26,7 @@
package java.lang.reflect;
import java.security.AccessController;
+import sun.reflect.Reflection;
import sun.reflect.ReflectionFactory;
import java.lang.annotation.Annotation;
@@ -201,4 +202,73 @@
public Annotation[] getDeclaredAnnotations() {
throw new AssertionError("All subclasses should override this method");
}
+
+
+ // Shared access checking logic.
+
+ // For non-public members or members in package-private classes,
+ // it is necessary to perform somewhat expensive security checks.
+ // If the security check succeeds for a given class, it will
+ // always succeed (it is not affected by the granting or revoking
+ // of permissions); we speed up the check in the common case by
+ // remembering the last Class for which the check succeeded.
+ //
+ // The simple security check for Constructor is to see if
+ // the caller has already been seen, verified, and cached.
+ // (See also Class.newInstance(), which uses a similar method.)
+ //
+ // A more complicated security check cache is needed for Method and Field
+ // The cache can be either null (empty cache), a 2-array of {caller,target},
+ // or a caller (with target implicitly equal to this.clazz).
+ // In the 2-array case, the target is always different from the clazz.
+ volatile Object securityCheckCache;
+
+ void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers)
+ throws IllegalAccessException
+ {
+ if (caller == clazz) { // quick check
+ return; // ACCESS IS OK
+ }
+ Object cache = securityCheckCache; // read volatile
+ Class<?> targetClass = clazz;
+ if (obj != null
+ && Modifier.isProtected(modifiers)
+ && ((targetClass = obj.getClass()) != clazz)) {
+ // Must match a 2-list of { caller, targetClass }.
+ if (cache instanceof Class[]) {
+ Class<?>[] cache2 = (Class<?>[]) cache;
+ if (cache2[1] == targetClass &&
+ cache2[0] == caller) {
+ return; // ACCESS IS OK
+ }
+ // (Test cache[1] first since range check for [1]
+ // subsumes range check for [0].)
+ }
+ } else if (cache == caller) {
+ // Non-protected case (or obj.class == this.clazz).
+ return; // ACCESS IS OK
+ }
+
+ // If no return, fall through to the slow path.
+ slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
+ }
+
+ // Keep all this slow stuff out of line:
+ void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,
+ Class<?> targetClass)
+ throws IllegalAccessException
+ {
+ Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
+
+ // Success: Update the cache.
+ Object cache = ((targetClass == clazz)
+ ? caller
+ : new Class<?>[] { caller, targetClass });
+
+ // Note: The two cache elements are not volatile,
+ // but they are effectively final. The Java memory model
+ // guarantees that the initializing stores for the cache
+ // elements will occur before the volatile write.
+ securityCheckCache = cache; // write volatile
+ }
}