jdk/src/share/classes/java/lang/reflect/AccessibleObject.java
changeset 9029 e92fcf58f684
parent 5506 202f599c92aa
child 14342 8435a30053c1
--- 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
+    }
 }