8010117: Annotate jdk caller sensitive methods with @sun.reflect.CallerSensitive
authormchung
Tue, 16 Apr 2013 21:39:52 -0700
changeset 16906 44dfee24cb71
parent 16905 0419f45c7761
child 16908 c8a0f2183fed
8010117: Annotate jdk caller sensitive methods with @sun.reflect.CallerSensitive Reviewed-by: jrose, alanb, twisti
jdk/make/java/java/FILES_c.gmk
jdk/make/java/java/mapfile-vers
jdk/make/java/java/reorder-i586
jdk/make/java/java/reorder-sparc
jdk/make/java/java/reorder-sparcv9
jdk/makefiles/mapfiles/libjava/mapfile-vers
jdk/makefiles/mapfiles/libjava/reorder-sparc
jdk/makefiles/mapfiles/libjava/reorder-sparcv9
jdk/makefiles/mapfiles/libjava/reorder-x86
jdk/src/share/classes/java/lang/Class.java
jdk/src/share/classes/java/lang/ClassLoader.java
jdk/src/share/classes/java/lang/Package.java
jdk/src/share/classes/java/lang/Runtime.java
jdk/src/share/classes/java/lang/SecurityManager.java
jdk/src/share/classes/java/lang/System.java
jdk/src/share/classes/java/lang/Thread.java
jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
jdk/src/share/classes/java/lang/invoke/MemberName.java
jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
jdk/src/share/classes/java/lang/invoke/MethodHandles.java
jdk/src/share/classes/java/lang/reflect/Constructor.java
jdk/src/share/classes/java/lang/reflect/Field.java
jdk/src/share/classes/java/lang/reflect/Method.java
jdk/src/share/classes/java/lang/reflect/Proxy.java
jdk/src/share/classes/java/security/AccessController.java
jdk/src/share/classes/java/sql/DriverManager.java
jdk/src/share/classes/java/util/ResourceBundle.java
jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
jdk/src/share/classes/java/util/logging/Logger.java
jdk/src/share/classes/javax/script/ScriptEngineManager.java
jdk/src/share/classes/sun/misc/Unsafe.java
jdk/src/share/classes/sun/reflect/CallerSensitive.java
jdk/src/share/classes/sun/reflect/Reflection.java
jdk/src/share/javavm/export/jvm.h
jdk/src/share/native/java/lang/ClassLoader.c
jdk/src/share/native/java/lang/ResourceBundle.c
jdk/src/share/native/java/lang/SecurityManager.c
jdk/src/share/native/sun/reflect/Reflection.c
jdk/test/Makefile
jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java
jdk/test/sun/reflect/CallerSensitive/MethodFinder.java
jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java
jdk/test/sun/reflect/Reflection/GetCallerClass.java
jdk/test/sun/reflect/Reflection/GetCallerClassTest.java
jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh
--- a/jdk/make/java/java/FILES_c.gmk	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/make/java/java/FILES_c.gmk	Tue Apr 16 21:39:52 2013 -0700
@@ -48,7 +48,6 @@
 	Proxy.c \
 	RandomAccessFile.c \
 	RandomAccessFile_md.c \
-	ResourceBundle.c \
 	Runtime.c \
 	SecurityManager.c \
 	Shutdown.c \
--- a/jdk/make/java/java/mapfile-vers	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/make/java/java/mapfile-vers	Tue Apr 16 21:39:52 2013 -0700
@@ -134,7 +134,6 @@
 		Java_java_lang_ClassLoader_00024NativeLibrary_load;
 		Java_java_lang_ClassLoader_00024NativeLibrary_unload;
 		Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
-		Java_java_lang_ClassLoader_getCaller; 
 		Java_java_lang_ClassLoader_registerNatives;
 		Java_java_lang_Compiler_registerNatives;
 		Java_java_lang_Double_longBitsToDouble;
@@ -233,7 +232,6 @@
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2;
 		Java_java_security_AccessController_getStackAccessControlContext;
 		Java_java_security_AccessController_getInheritedAccessControlContext;
-		Java_java_util_ResourceBundle_getClassContext;
 		Java_java_util_TimeZone_getSystemTimeZoneID;
 		Java_java_util_TimeZone_getSystemGMTOffsetID;
 		Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
--- a/jdk/make/java/java/reorder-i586	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/make/java/java/reorder-i586	Tue Apr 16 21:39:52 2013 -0700
@@ -73,7 +73,6 @@
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/jdk/make/java/java/reorder-sparc	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/make/java/java/reorder-sparc	Tue Apr 16 21:39:52 2013 -0700
@@ -78,7 +78,6 @@
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/jdk/make/java/java/reorder-sparcv9	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/make/java/java/reorder-sparcv9	Tue Apr 16 21:39:52 2013 -0700
@@ -74,7 +74,6 @@
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/jdk/makefiles/mapfiles/libjava/mapfile-vers	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/makefiles/mapfiles/libjava/mapfile-vers	Tue Apr 16 21:39:52 2013 -0700
@@ -134,7 +134,6 @@
 		Java_java_lang_ClassLoader_00024NativeLibrary_load;
 		Java_java_lang_ClassLoader_00024NativeLibrary_unload;
 		Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
-		Java_java_lang_ClassLoader_getCaller; 
 		Java_java_lang_ClassLoader_registerNatives;
 		Java_java_lang_Compiler_registerNatives;
 		Java_java_lang_Double_longBitsToDouble;
@@ -233,7 +232,6 @@
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2;
 		Java_java_security_AccessController_getStackAccessControlContext;
 		Java_java_security_AccessController_getInheritedAccessControlContext;
-		Java_java_util_ResourceBundle_getClassContext;
 		Java_java_util_TimeZone_getSystemTimeZoneID;
 		Java_java_util_TimeZone_getSystemGMTOffsetID;
 		Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
--- a/jdk/makefiles/mapfiles/libjava/reorder-sparc	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/makefiles/mapfiles/libjava/reorder-sparc	Tue Apr 16 21:39:52 2013 -0700
@@ -78,7 +78,6 @@
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/jdk/makefiles/mapfiles/libjava/reorder-sparcv9	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/makefiles/mapfiles/libjava/reorder-sparcv9	Tue Apr 16 21:39:52 2013 -0700
@@ -74,7 +74,6 @@
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/jdk/makefiles/mapfiles/libjava/reorder-x86	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/makefiles/mapfiles/libjava/reorder-x86	Tue Apr 16 21:39:52 2013 -0700
@@ -73,7 +73,6 @@
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/jdk/src/share/classes/java/lang/Class.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/Class.java	Tue Apr 16 21:39:52 2013 -0700
@@ -53,6 +53,7 @@
 import java.util.HashMap;
 import java.util.Objects;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
 import sun.reflect.ConstantPool;
 import sun.reflect.Reflection;
 import sun.reflect.ReflectionFactory;
@@ -250,9 +251,11 @@
      *            by this method fails
      * @exception ClassNotFoundException if the class cannot be located
      */
+    @CallerSensitive
     public static Class<?> forName(String className)
                 throws ClassNotFoundException {
-        return forName0(className, true, ClassLoader.getCallerClassLoader());
+        return forName0(className, true,
+                        ClassLoader.getClassLoader(Reflection.getCallerClass()));
     }
 
 
@@ -317,6 +320,7 @@
      * @see       java.lang.ClassLoader
      * @since     1.2
      */
+    @CallerSensitive
     public static Class<?> forName(String name, boolean initialize,
                                    ClassLoader loader)
         throws ClassNotFoundException
@@ -324,7 +328,7 @@
         if (sun.misc.VM.isSystemDomainLoader(loader)) {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                ClassLoader ccl = ClassLoader.getCallerClassLoader();
+                ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
                 if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                     sm.checkPermission(
                         SecurityConstants.GET_CLASSLOADER_PERMISSION);
@@ -386,18 +390,14 @@
      *             </ul>
      *
      */
+    @CallerSensitive
     public T newInstance()
         throws InstantiationException, IllegalAccessException
     {
         if (System.getSecurityManager() != null) {
-            checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
+            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
         }
-        return newInstance0();
-    }
 
-    private T newInstance0()
-        throws InstantiationException, IllegalAccessException
-    {
         // NOTE: the following code may not be strictly correct under
         // the current Java memory model.
 
@@ -432,7 +432,7 @@
         // Security check (same as in java.lang.reflect.Constructor)
         int modifiers = tmpConstructor.getModifiers();
         if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
-            Class<?> caller = Reflection.getCallerClass(3);
+            Class<?> caller = Reflection.getCallerClass();
             if (newInstanceCallerCache != caller) {
                 Reflection.ensureMemberAccess(caller, this, null, modifiers);
                 newInstanceCallerCache = caller;
@@ -674,16 +674,14 @@
      * @see SecurityManager#checkPermission
      * @see java.lang.RuntimePermission
      */
+    @CallerSensitive
     public ClassLoader getClassLoader() {
         ClassLoader cl = getClassLoader0();
         if (cl == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = ClassLoader.getCallerClassLoader();
-            if (ClassLoader.needsClassLoaderPermissionCheck(ccl, cl)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
         }
         return cl;
     }
@@ -1392,11 +1390,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Class<?>[] getClasses() {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
 
         // Privileged so this implementation can look at DECLARED classes,
         // something the caller might not have privilege to do.  The code here
@@ -1467,11 +1463,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field[] getFields() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return copyFields(privateGetPublicFields(null));
     }
 
@@ -1518,11 +1512,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method[] getMethods() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return copyMethods(privateGetPublicMethods());
     }
 
@@ -1567,11 +1559,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<?>[] getConstructors() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return copyConstructors(privateGetDeclaredConstructors(true));
     }
 
@@ -1625,12 +1615,10 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field getField(String name)
         throws NoSuchFieldException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         Field field = getField0(name);
         if (field == null) {
             throw new NoSuchFieldException(name);
@@ -1710,12 +1698,10 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method getMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         Method method = getMethod0(name, parameterTypes);
         if (method == null) {
             throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
@@ -1764,12 +1750,10 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<T> getConstructor(Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return getConstructor0(parameterTypes, Member.PUBLIC);
     }
 
@@ -1807,11 +1791,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Class<?>[] getDeclaredClasses() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), false);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
         return getDeclaredClasses0();
     }
 
@@ -1851,11 +1833,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field[] getDeclaredFields() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return copyFields(privateGetDeclaredFields(false));
     }
 
@@ -1899,11 +1879,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method[] getDeclaredMethods() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return copyMethods(privateGetDeclaredMethods(false));
     }
 
@@ -1944,11 +1922,9 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return copyConstructors(privateGetDeclaredConstructors(false));
     }
 
@@ -1987,12 +1963,10 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field getDeclaredField(String name)
         throws NoSuchFieldException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         Field field = searchFields(privateGetDeclaredFields(false), name);
         if (field == null) {
             throw new NoSuchFieldException(name);
@@ -2042,12 +2016,10 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
         if (method == null) {
             throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
@@ -2092,12 +2064,10 @@
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return getConstructor0(parameterTypes, Member.DECLARED);
     }
 
@@ -2255,23 +2225,40 @@
      */
     static native Class<?> getPrimitiveClass(String name);
 
+    private static boolean isCheckMemberAccessOverridden(SecurityManager smgr) {
+        if (smgr.getClass() == SecurityManager.class) return false;
+
+        Class<?>[] paramTypes = new Class<?>[] {Class.class, int.class};
+        return smgr.getClass().getMethod0("checkMemberAccess", paramTypes).
+                getDeclaringClass() != SecurityManager.class;
+    }
 
     /*
      * Check if client is allowed to access members.  If access is denied,
      * throw a SecurityException.
      *
-     * Be very careful not to change the stack depth of this checkMemberAccess
-     * call for security reasons.
-     * See java.lang.SecurityManager.checkMemberAccess.
-     *
      * <p> Default policy: allow all clients access with normal Java access
      * control.
      */
-    private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) {
-        SecurityManager s = System.getSecurityManager();
+    private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {
+        final SecurityManager s = System.getSecurityManager();
         if (s != null) {
-            s.checkMemberAccess(this, which);
-            ClassLoader cl = getClassLoader0();
+            final ClassLoader ccl = ClassLoader.getClassLoader(caller);
+            final ClassLoader cl = getClassLoader0();
+            if (!isCheckMemberAccessOverridden(s)) {
+                // Inlined SecurityManager.checkMemberAccess
+                if (which != Member.PUBLIC) {
+                    if (ccl != cl) {
+                        s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+                    }
+                }
+            } else {
+                // Don't refactor; otherwise break the stack depth for
+                // checkMemberAccess of subclasses of SecurityManager as specified.
+                s.checkMemberAccess(this, which);
+            }
+
+
             if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
                 String name = this.getName();
                 int i = name.lastIndexOf('.');
--- a/jdk/src/share/classes/java/lang/ClassLoader.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java	Tue Apr 16 21:39:52 2013 -0700
@@ -55,6 +55,7 @@
 import sun.misc.Resource;
 import sun.misc.URLClassPath;
 import sun.misc.VM;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
@@ -1159,11 +1160,6 @@
         return java.util.Collections.emptyEnumeration();
     }
 
-    // index 0: java.lang.ClassLoader.class
-    // index 1: the immediate caller of index 0.
-    // index 2: the immediate caller of index 1.
-    private static native Class<? extends ClassLoader> getCaller(int index);
-
     /**
      * Registers the caller as parallel capable.</p>
      * The registration succeeds if and only if all of the following
@@ -1179,8 +1175,11 @@
      *
      * @since   1.7
      */
+    @CallerSensitive
     protected static boolean registerAsParallelCapable() {
-        return ParallelLoaders.register(getCaller(1));
+        Class<? extends ClassLoader> callerClass =
+            Reflection.getCallerClass().asSubclass(ClassLoader.class);
+        return ParallelLoaders.register(callerClass);
     }
 
     /**
@@ -1340,15 +1339,13 @@
      *
      * @since  1.2
      */
+    @CallerSensitive
     public final ClassLoader getParent() {
         if (parent == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = getCallerClassLoader();
-            if (needsClassLoaderPermissionCheck(ccl, this)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            checkClassLoaderPermission(this, Reflection.getCallerClass());
         }
         return parent;
     }
@@ -1408,6 +1405,7 @@
      *
      * @revised  1.4
      */
+    @CallerSensitive
     public static ClassLoader getSystemClassLoader() {
         initSystemClassLoader();
         if (scl == null) {
@@ -1415,10 +1413,7 @@
         }
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = getCallerClassLoader();
-            if (needsClassLoaderPermissionCheck(ccl, scl)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            checkClassLoaderPermission(scl, Reflection.getCallerClass());
         }
         return scl;
     }
@@ -1471,8 +1466,8 @@
     // class loader 'from' is same as class loader 'to' or an ancestor
     // of 'to'.  The class loader in a system domain can access
     // any class loader.
-    static boolean needsClassLoaderPermissionCheck(ClassLoader from,
-                                                   ClassLoader to)
+    private static boolean needsClassLoaderPermissionCheck(ClassLoader from,
+                                                           ClassLoader to)
     {
         if (from == to)
             return false;
@@ -1483,13 +1478,8 @@
         return !to.isAncestor(from);
     }
 
-    // Returns the invoker's class loader, or null if none.
-    // NOTE: This must always be invoked when there is exactly one intervening
-    // frame from the core libraries on the stack between this method's
-    // invocation and the desired invoker.
-    static ClassLoader getCallerClassLoader() {
-        // NOTE use of more generic Reflection.getCallerClass()
-        Class<?> caller = Reflection.getCallerClass(3);
+    // Returns the class's class loader, or null if none.
+    static ClassLoader getClassLoader(Class<?> caller) {
         // This can be null if the VM is requesting it
         if (caller == null) {
             return null;
@@ -1498,6 +1488,17 @@
         return caller.getClassLoader0();
     }
 
+    static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // caller can be null if the VM is requesting it
+            ClassLoader ccl = getClassLoader(caller);
+            if (needsClassLoaderPermissionCheck(ccl, cl)) {
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            }
+        }
+    }
+
     // The class loader for the system
     // @GuardedBy("ClassLoader.class")
     private static ClassLoader scl;
--- a/jdk/src/share/classes/java/lang/Package.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/Package.java	Tue Apr 16 21:39:52 2013 -0700
@@ -49,6 +49,8 @@
 import java.util.Iterator;
 
 import sun.net.www.ParseUtil;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 import java.lang.annotation.Annotation;
 
@@ -273,8 +275,9 @@
      * @return the package of the requested name. It may be null if no package
      *          information is available from the archive or codebase.
      */
+    @CallerSensitive
     public static Package getPackage(String name) {
-        ClassLoader l = ClassLoader.getCallerClassLoader();
+        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
         if (l != null) {
             return l.getPackage(name);
         } else {
@@ -294,8 +297,9 @@
      * @return a new array of packages known to the callers {@code ClassLoader}
      * instance.  An zero length array is returned if none are known.
      */
+    @CallerSensitive
     public static Package[] getPackages() {
-        ClassLoader l = ClassLoader.getCallerClassLoader();
+        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
         if (l != null) {
             return l.getPackages();
         } else {
--- a/jdk/src/share/classes/java/lang/Runtime.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/Runtime.java	Tue Apr 16 21:39:52 2013 -0700
@@ -27,6 +27,8 @@
 
 import java.io.*;
 import java.util.StringTokenizer;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * Every Java application has a single instance of class
@@ -790,8 +792,9 @@
      * @see        java.lang.SecurityException
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public void load(String filename) {
-        load0(System.getCallerClass(), filename);
+        load0(Reflection.getCallerClass(), filename);
     }
 
     synchronized void load0(Class<?> fromClass, String filename) {
@@ -850,8 +853,9 @@
      * @see        java.lang.SecurityException
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public void loadLibrary(String libname) {
-        loadLibrary0(System.getCallerClass(), libname);
+        loadLibrary0(Reflection.getCallerClass(), libname);
     }
 
     synchronized void loadLibrary0(Class<?> fromClass, String libname) {
--- a/jdk/src/share/classes/java/lang/SecurityManager.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/SecurityManager.java	Tue Apr 16 21:39:52 2013 -0700
@@ -36,10 +36,10 @@
 import java.net.NetPermission;
 import java.util.Hashtable;
 import java.net.InetAddress;
-import java.lang.reflect.Member;
 import java.lang.reflect.*;
 import java.net.URL;
 
+import sun.reflect.CallerSensitive;
 import sun.security.util.SecurityConstants;
 
 /**
@@ -1679,6 +1679,7 @@
      * @since JDK1.1
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @CallerSensitive
     public void checkMemberAccess(Class<?> clazz, int which) {
         if (clazz == null) {
             throw new NullPointerException("class can't be null");
--- a/jdk/src/share/classes/java/lang/System.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/System.java	Tue Apr 16 21:39:52 2013 -0700
@@ -35,6 +35,7 @@
 import java.nio.channels.Channel;
 import java.nio.channels.spi.SelectorProvider;
 import sun.nio.ch.Interruptible;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 import sun.reflect.annotation.AnnotationType;
@@ -1072,8 +1073,9 @@
      * @see        java.lang.Runtime#load(java.lang.String)
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public static void load(String filename) {
-        Runtime.getRuntime().load0(getCallerClass(), filename);
+        Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
     }
 
     /**
@@ -1107,8 +1109,9 @@
      * @see        java.lang.Runtime#loadLibrary(java.lang.String)
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public static void loadLibrary(String libname) {
-        Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
+        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
     }
 
     /**
@@ -1245,10 +1248,4 @@
             }
         });
     }
-
-    /* returns the class of the caller. */
-    static Class<?> getCallerClass() {
-        // NOTE use of more generic Reflection.getCallerClass()
-        return Reflection.getCallerClass(3);
-    }
 }
--- a/jdk/src/share/classes/java/lang/Thread.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/Thread.java	Tue Apr 16 21:39:52 2013 -0700
@@ -37,6 +37,8 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.locks.LockSupport;
 import sun.nio.ch.Interruptible;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
 
@@ -1443,15 +1445,14 @@
      *
      * @since 1.2
      */
+    @CallerSensitive
     public ClassLoader getContextClassLoader() {
         if (contextClassLoader == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = ClassLoader.getCallerClassLoader();
-            if (ClassLoader.needsClassLoaderPermissionCheck(ccl, contextClassLoader)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            ClassLoader.checkClassLoaderPermission(contextClassLoader,
+                                                   Reflection.getCallerClass());
         }
         return contextClassLoader;
     }
--- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Tue Apr 16 21:39:52 2013 -0700
@@ -709,7 +709,9 @@
             InvokerBytecodeGenerator.maybeDump(className, classFile);
             Class<? extends BoundMethodHandle> bmhClass =
                 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
-                UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
+                UNSAFE.defineClass(className, classFile, 0, classFile.length,
+                                   BoundMethodHandle.class.getClassLoader(), null)
+                    .asSubclass(BoundMethodHandle.class);
             UNSAFE.ensureClassInitialized(bmhClass);
 
             return bmhClass;
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java	Tue Apr 16 21:39:52 2013 -0700
@@ -391,10 +391,11 @@
 
     // private flags, not part of RECOGNIZED_MODIFIERS:
     static final int
-            IS_METHOD      = MN_IS_METHOD,      // method (not constructor)
-            IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
-            IS_FIELD       = MN_IS_FIELD,       // field
-            IS_TYPE        = MN_IS_TYPE;        // nested type
+            IS_METHOD        = MN_IS_METHOD,        // method (not constructor)
+            IS_CONSTRUCTOR   = MN_IS_CONSTRUCTOR,   // constructor
+            IS_FIELD         = MN_IS_FIELD,         // field
+            IS_TYPE          = MN_IS_TYPE,          // nested type
+            CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected
 
     static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
     static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
@@ -430,6 +431,10 @@
     public boolean isPackage() {
         return !testAnyFlags(ALL_ACCESS);
     }
+    /** Query whether this member has a CallerSensitive annotation. */
+    public boolean isCallerSensitive() {
+        return testAllFlags(CALLER_SENSITIVE);
+    }
 
     /** Utility method to query whether this member is accessible from a given lookup class. */
     public boolean isAccessibleFrom(Class<?> lookupClass) {
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Apr 16 21:39:52 2013 -0700
@@ -34,6 +34,8 @@
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyType;
 import sun.invoke.util.Wrapper;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import static java.lang.invoke.LambdaForm.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@@ -891,9 +893,11 @@
             }
         }
 
+        @CallerSensitive
         private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
-            final int FRAME_COUNT_ARG = 2;  // [0] Reflection [1] BindCaller [2] Expected
-            Class<?> actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG);
+            // This method is called via MH_checkCallerClass and so it's
+            // correct to ask for the immediate caller here.
+            Class<?> actual = Reflection.getCallerClass();
             if (actual != expected && actual != expected2)
                 throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
                                         +(expected == expected2 ? "" : ", or else "+expected2.getName()));
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Apr 16 21:39:52 2013 -0700
@@ -26,7 +26,6 @@
 package java.lang.invoke;
 
 import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Field;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.MethodHandleStatics.*;
@@ -34,7 +33,7 @@
 
 /**
  * The JVM interface for the method handles package is all here.
- * This is an interface internal and private to an implemetantion of JSR 292.
+ * This is an interface internal and private to an implementation of JSR 292.
  * <em>This class is not part of the JSR 292 standard.</em>
  * @author jrose
  */
@@ -101,6 +100,7 @@
                 MN_IS_CONSTRUCTOR      = 0x00020000, // constructor
                 MN_IS_FIELD            = 0x00040000, // field
                 MN_IS_TYPE             = 0x00080000, // nested type
+                MN_CALLER_SENSITIVE    = 0x00100000, // @CallerSensitive annotation detected
                 MN_REFERENCE_KIND_SHIFT = 24, // refKind
                 MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
                 // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
@@ -391,129 +391,24 @@
      * I.e., does it call Reflection.getCallerClass or a similer method
      * to ask about the identity of its caller?
      */
-    // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive.
     static boolean isCallerSensitive(MemberName mem) {
         if (!mem.isInvocable())  return false;  // fields are not caller sensitive
+
+        return mem.isCallerSensitive() || canBeCalledVirtual(mem);
+    }
+
+    static boolean canBeCalledVirtual(MemberName mem) {
+        assert(mem.isInvocable());
         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":
-            return defc == java.lang.invoke.MethodHandles.class;
-        case "findStatic":
-        case "findVirtual":
-        case "findConstructor":
-        case "findSpecial":
-        case "findGetter":
-        case "findSetter":
-        case "findStaticGetter":
-        case "findStaticSetter":
-        case "bind":
-        case "unreflect":
-        case "unreflectSpecial":
-        case "unreflectConstructor":
-        case "unreflectGetter":
-        case "unreflectSetter":
-            return defc == java.lang.invoke.MethodHandles.Lookup.class;
-        case "invoke":
-            return defc == java.lang.reflect.Method.class;
-        case "get":
-        case "getBoolean":
-        case "getByte":
-        case "getChar":
-        case "getShort":
-        case "getInt":
-        case "getLong":
-        case "getFloat":
-        case "getDouble":
-        case "set":
-        case "setBoolean":
-        case "setByte":
-        case "setChar":
-        case "setShort":
-        case "setInt":
-        case "setLong":
-        case "setFloat":
-        case "setDouble":
-            return defc == java.lang.reflect.Field.class;
-        case "newInstance":
-            if (defc == java.lang.reflect.Constructor.class)  return true;
-            if (defc == java.lang.Class.class)  return true;
-            break;
-        case "forName":
-        case "getClassLoader":
-        case "getClasses":
-        case "getFields":
-        case "getMethods":
-        case "getConstructors":
-        case "getDeclaredClasses":
-        case "getDeclaredFields":
-        case "getDeclaredMethods":
-        case "getDeclaredConstructors":
-        case "getField":
-        case "getMethod":
-        case "getConstructor":
-        case "getDeclaredField":
-        case "getDeclaredMethod":
-        case "getDeclaredConstructor":
-            return defc == java.lang.Class.class;
-        case "getConnection":
-        case "getDriver":
-        case "getDrivers":
-        case "deregisterDriver":
-            return defc == getClass("java.sql.DriverManager");
-        case "newUpdater":
-            if (defc == java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class)  return true;
-            if (defc == java.util.concurrent.atomic.AtomicLongFieldUpdater.class)  return true;
-            if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class)  return true;
-            break;
         case "getContextClassLoader":
             return canBeCalledVirtual(mem, java.lang.Thread.class);
-        case "getPackage":
-        case "getPackages":
-            return defc == java.lang.Package.class;
-        case "getParent":
-        case "getSystemClassLoader":
-            return defc == java.lang.ClassLoader.class;
-        case "load":
-        case "loadLibrary":
-            if (defc == java.lang.Runtime.class)  return true;
-            if (defc == java.lang.System.class)  return true;
-            break;
-        case "getCallerClass":
-            if (defc == sun.reflect.Reflection.class)  return true;
-            if (defc == java.lang.System.class)  return true;
-            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;
-        case "asInterfaceInstance":
-            return defc == java.lang.invoke.MethodHandleProxies.class;
-        case "getBundle":
-        case "clearCache":
-            return defc == java.util.ResourceBundle.class;
         }
         return false;
     }
 
-    // avoid static dependency to a class in other modules
-    private static Class<?> getClass(String cn) {
-        try {
-            return Class.forName(cn, false,
-                                 MethodHandleNatives.class.getClassLoader());
-        } catch (ClassNotFoundException e) {
-            throw new InternalError(e);
-        }
-    }
     static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
         Class<?> symbolicRefClass = symbolicRef.getDeclaringClass();
         if (symbolicRefClass == definingClass)  return true;
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Tue Apr 16 21:39:52 2013 -0700
@@ -30,6 +30,7 @@
 import java.security.PrivilegedAction;
 import sun.invoke.WrapperInstance;
 import java.util.ArrayList;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
 
@@ -137,14 +138,14 @@
     // entry points, must be covered by hand-written or automatically
     // generated adapter classes.
     //
+    @CallerSensitive
     public static
     <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
         if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
             throw new IllegalArgumentException("not a public interface: "+intfc.getName());
         final MethodHandle mh;
         if (System.getSecurityManager() != null) {
-            final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller
-            final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
+            final Class<?> caller = Reflection.getCallerClass();
             final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
             ReflectUtil.checkProxyPackageAccess(ccl, intfc);
             mh = ccl != null ? bindCaller(target, caller) : target;
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Tue Apr 16 21:39:52 2013 -0700
@@ -26,13 +26,17 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyAccess;
 import sun.invoke.util.Wrapper;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Arrays;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 
@@ -65,8 +69,9 @@
      * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
      * Do not store it in place where untrusted code can access it.
      */
+    @CallerSensitive
     public static Lookup lookup() {
-        return new Lookup();
+        return new Lookup(Reflection.getCallerClass());
     }
 
     /**
@@ -416,20 +421,13 @@
          * for method handle creation.
          * Must be called by from a method in this package,
          * which in turn is called by a method not in this package.
-         * <p>
-         * Also, don't make it private, lest javac interpose
-         * an access$N method.
          */
-        Lookup() {
-            this(getCallerClassAtEntryPoint(false), ALL_MODES);
+        Lookup(Class<?> lookupClass) {
+            this(lookupClass, ALL_MODES);
             // make sure we haven't accidentally picked up a privileged class:
             checkUnprivilegedlookupClass(lookupClass);
         }
 
-        Lookup(Class<?> lookupClass) {
-            this(lookupClass, ALL_MODES);
-        }
-
         private Lookup(Class<?> lookupClass, int allowedModes) {
             this.lookupClass = lookupClass;
             this.allowedModes = allowedModes;
@@ -554,20 +552,6 @@
             }
         }
 
-        /* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */
-        private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) {
-            final int CALLER_DEPTH = 4;
-            //  Stack for the constructor entry point (inSubroutine=false):
-            // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
-            // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
-            //  The stack is slightly different for a subroutine of a Lookup.find* method:
-            // 2: Lookup.*, 3: Lookup.find*.*, 4: caller
-            // Note:  This should be the only use of getCallerClass in this file.
-            assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class);
-            assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class));
-            return Reflection.getCallerClass(CALLER_DEPTH);
-        }
-
         /**
          * Produces a method handle for a static method.
          * The type of the method handle will be that of the method.
@@ -594,12 +578,14 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public
         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
-            return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            return getDirectMethod(REF_invokeStatic, refc, method,
+                                   findBoundCallerClass(method, callerClass));
         }
 
         /**
@@ -645,6 +631,7 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             if (refc == MethodHandle.class) {
                 MethodHandle mh = findVirtualForMH(name, type);
@@ -652,9 +639,10 @@
             }
             byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
             MemberName method = resolveOrFail(refKind, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);
-            return getDirectMethod(refKind, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            return getDirectMethod(refKind, refc, method,
+                                   findBoundCallerClass(method, callerClass));
         }
         private MethodHandle findVirtualForMH(String name, MethodType type) {
             // these names require special lookups because of the implicit MethodType argument
@@ -691,10 +679,11 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             String name = "<init>";
             MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
-            checkSecurityManager(refc, ctor);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, ctor, Reflection.getCallerClass());
             return getDirectConstructor(refc, ctor);
         }
 
@@ -732,14 +721,16 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
             checkSpecialCaller(specialCaller);
             Lookup specialLookup = this.in(specialCaller);
             MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);
-            return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method,
+                                                 findBoundCallerClass(method, callerClass));
         }
 
         /**
@@ -759,9 +750,10 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_getField, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_getField, refc, field);
         }
 
@@ -782,9 +774,10 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_putField, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_putField, refc, field);
         }
 
@@ -804,9 +797,10 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_getStatic, refc, field);
         }
 
@@ -826,9 +820,10 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_putStatic, refc, field);
         }
 
@@ -878,12 +873,14 @@
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             Class<? extends Object> refc = receiver.getClass(); // may get NPE
             MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
-            MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method,
+                                                        findBoundCallerClass(method, callerClass));
             return mh.bindReceiver(receiver).setVarargs(method);
         }
 
@@ -908,13 +905,14 @@
          *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if the argument is null
          */
+        @CallerSensitive
         public MethodHandle unreflect(Method m) throws IllegalAccessException {
             MemberName method = new MemberName(m);
             byte refKind = method.getReferenceKind();
             if (refKind == REF_invokeSpecial)
                 refKind = REF_invokeVirtual;
             assert(method.isMethod());
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
+            Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
         }
@@ -940,12 +938,13 @@
          *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
             checkSpecialCaller(specialCaller);
             Lookup specialLookup = this.in(specialCaller);
             MemberName method = new MemberName(m, true);
             assert(method.isMethod());
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
+            Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
             // ignore m.isAccessible:  this is a new kind of access
             return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
         }
@@ -1050,20 +1049,35 @@
          * 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<?> findBoundCallerClass(MemberName m, Class<?> callerAtEntryPoint) {
             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));
+                               : callerAtEntryPoint);
             }
             return callerClass;
         }
+
+        /**
+         * Determine whether a security manager has an overridden
+         * SecurityManager.checkMemberAccess method.
+         */
+        private boolean isCheckMemberAccessOverridden(SecurityManager sm) {
+            final Class<? extends SecurityManager> cls = sm.getClass();
+            if (cls == SecurityManager.class) return false;
+
+            try {
+                return cls.getMethod("checkMemberAccess", Class.class, int.class).
+                    getDeclaringClass() != SecurityManager.class;
+            } catch (NoSuchMethodException e) {
+                throw new InternalError("should not reach here");
+            }
+        }
+
         /**
          * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
          * Determines a trustable caller class to compare with refc, the symbolic reference class.
@@ -1071,46 +1085,55 @@
          * 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) {
+        void checkSecurityManager(Class<?> refc, MemberName m, Class<?> caller) {
             SecurityManager smgr = System.getSecurityManager();
             if (smgr == null)  return;
             if (allowedModes == TRUSTED)  return;
+
+            final boolean overridden = isCheckMemberAccessOverridden(smgr);
             // Step 1:
-            smgr.checkMemberAccess(refc, Member.PUBLIC);
+            {
+                // Default policy is to allow Member.PUBLIC; no need to check
+                // permission if SecurityManager is the default implementation
+                final int which = Member.PUBLIC;
+                final Class<?> clazz = refc;
+                if (overridden) {
+                    // Don't refactor; otherwise break the stack depth for
+                    // checkMemberAccess of subclasses of SecurityManager as specified.
+                    smgr.checkMemberAccess(clazz, which);
+                }
+            }
+
             // Step 2:
             Class<?> callerClass = ((allowedModes & PRIVATE) != 0
                                     ? lookupClass  // for strong access modes, no extra check
-                                    // next line does stack walk magic; do not refactor:
-                                    : getCallerClassAtEntryPoint(true));
+                                    : caller);
             if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
                 (callerClass != lookupClass &&
                  !VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
                 smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
+
             // Step 3:
             if (m.isPublic()) return;
             Class<?> defc = m.getDeclaringClass();
-            smgr.checkMemberAccess(defc, Member.DECLARED);  // STACK WALK HERE
+            {
+                // Inline SecurityManager.checkMemberAccess
+                final int which = Member.DECLARED;
+                final Class<?> clazz = defc;
+                if (!overridden) {
+                    if (caller.getClassLoader() != clazz.getClassLoader()) {
+                        smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+                    }
+                } else {
+                    // Don't refactor; otherwise break the stack depth for
+                    // checkMemberAccess of subclasses of SecurityManager as specified.
+                    smgr.checkMemberAccess(clazz, which);
+                }
+            }
+
             // Step 4:
             if (defc != refc)
                 smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
-
-            // Comment from SM.checkMemberAccess, where which=DECLARED:
-            /*
-             * stack depth of 4 should be the caller of one of the
-             * methods in java.lang.Class that invoke checkMember
-             * access. The stack should look like:
-             *
-             * someCaller                        [3]
-             * java.lang.Class.someReflectionAPI [2]
-             * java.lang.Class.checkMemberAccess [1]
-             * SecurityManager.checkMemberAccess [0]
-             *
-             */
-            // For us it is this stack:
-            // someCaller                        [3]
-            // Lookup.findSomeMember             [2]
-            // Lookup.checkSecurityManager       [1]
-            // SecurityManager.checkMemberAccess [0]
         }
 
         void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java	Tue Apr 16 21:39:52 2013 -0700
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import sun.reflect.CallerSensitive;
 import sun.reflect.ConstructorAccessor;
 import sun.reflect.Reflection;
 import sun.reflect.generics.repository.ConstructorRepository;
@@ -392,14 +393,14 @@
      * @exception ExceptionInInitializerError if the initialization provoked
      *              by this method fails.
      */
+    @CallerSensitive
     public T newInstance(Object ... initargs)
         throws InstantiationException, IllegalAccessException,
                IllegalArgumentException, InvocationTargetException
     {
         if (!override) {
             if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass(2);
-
+                Class<?> caller = Reflection.getCallerClass();
                 checkAccess(caller, clazz, null, modifiers);
             }
         }
--- a/jdk/src/share/classes/java/lang/reflect/Field.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java	Tue Apr 16 21:39:52 2013 -0700
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import sun.reflect.CallerSensitive;
 import sun.reflect.FieldAccessor;
 import sun.reflect.Reflection;
 import sun.reflect.generics.repository.FieldRepository;
@@ -376,9 +377,16 @@
      * @exception ExceptionInInitializerError if the initialization provoked
      *              by this method fails.
      */
+    @CallerSensitive
     public Object get(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).get(obj);
     }
 
@@ -404,9 +412,16 @@
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public boolean getBoolean(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getBoolean(obj);
     }
 
@@ -432,9 +447,16 @@
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public byte getByte(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getByte(obj);
     }
 
@@ -462,9 +484,16 @@
      *              by this method fails.
      * @see Field#get
      */
+    @CallerSensitive
     public char getChar(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getChar(obj);
     }
 
@@ -492,9 +521,16 @@
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public short getShort(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getShort(obj);
     }
 
@@ -522,9 +558,16 @@
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public int getInt(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getInt(obj);
     }
 
@@ -552,9 +595,16 @@
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public long getLong(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getLong(obj);
     }
 
@@ -582,9 +632,16 @@
      *              by this method fails.
      * @see Field#get
      */
+    @CallerSensitive
     public float getFloat(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getFloat(obj);
     }
 
@@ -612,9 +669,16 @@
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public double getDouble(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getDouble(obj);
     }
 
@@ -684,9 +748,16 @@
      * @exception ExceptionInInitializerError if the initialization provoked
      *              by this method fails.
      */
+    @CallerSensitive
     public void set(Object obj, Object value)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).set(obj, value);
     }
 
@@ -714,9 +785,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setBoolean(Object obj, boolean z)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setBoolean(obj, z);
     }
 
@@ -744,9 +822,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setByte(Object obj, byte b)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setByte(obj, b);
     }
 
@@ -774,9 +859,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setChar(Object obj, char c)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setChar(obj, c);
     }
 
@@ -804,9 +896,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setShort(Object obj, short s)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setShort(obj, s);
     }
 
@@ -834,9 +933,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setInt(Object obj, int i)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setInt(obj, i);
     }
 
@@ -864,9 +970,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setLong(Object obj, long l)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setLong(obj, l);
     }
 
@@ -894,9 +1007,16 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setFloat(Object obj, float f)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setFloat(obj, f);
     }
 
@@ -924,20 +1044,26 @@
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setDouble(Object obj, double d)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setDouble(obj, d);
     }
 
-    // Convenience routine which performs security checks
+    // security check is done before calling this method
     private FieldAccessor getFieldAccessor(Object obj)
         throws IllegalAccessException
     {
-        doSecurityCheck(obj);
         boolean ov = override;
-        FieldAccessor a = (ov)? overrideFieldAccessor : fieldAccessor;
-        return (a != null)? a : acquireFieldAccessor(ov);
+        FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
+        return (a != null) ? a : acquireFieldAccessor(ov);
     }
 
     // NOTE that there is no synchronization used here. It is correct
@@ -982,19 +1108,6 @@
         }
     }
 
-    // NOTE: be very careful if you change the stack depth of this
-    // routine. The depth of the "getCallerClass" call is hardwired so
-    // that the compiler can have an easier time if this gets inlined.
-    private void doSecurityCheck(Object obj) throws IllegalAccessException {
-        if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass(4);
-
-                checkAccess(caller, clazz, obj, modifiers);
-            }
-        }
-    }
-
     /**
      * @throws NullPointerException {@inheritDoc}
      * @since 1.5
--- a/jdk/src/share/classes/java/lang/reflect/Method.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java	Tue Apr 16 21:39:52 2013 -0700
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import sun.reflect.CallerSensitive;
 import sun.reflect.MethodAccessor;
 import sun.reflect.Reflection;
 import sun.reflect.generics.repository.MethodRepository;
@@ -472,14 +473,14 @@
      * @exception ExceptionInInitializerError if the initialization
      * provoked by this method fails.
      */
+    @CallerSensitive
     public Object invoke(Object obj, Object... args)
         throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException
     {
         if (!override) {
             if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass(1);
-
+                Class<?> caller = Reflection.getCallerClass();
                 checkAccess(caller, clazz, obj, modifiers);
             }
         }
--- a/jdk/src/share/classes/java/lang/reflect/Proxy.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java	Tue Apr 16 21:39:52 2013 -0700
@@ -39,6 +39,8 @@
 import java.util.List;
 import java.util.WeakHashMap;
 import sun.misc.ProxyGenerator;
+import sun.misc.VM;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
 import sun.security.util.SecurityConstants;
@@ -408,28 +410,21 @@
      * @throws  NullPointerException if the {@code interfaces} array
      *          argument or any of its elements are {@code null}
      */
+    @CallerSensitive
     public static Class<?> getProxyClass(ClassLoader loader,
                                          Class<?>... interfaces)
         throws IllegalArgumentException
     {
-        return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
-    }
-
-    private static void checkProxyLoader(ClassLoader ccl,
-                                         ClassLoader loader)
-    {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            if (loader == null && ccl != null) {
-                if (!ProxyAccessHelper.allowNullLoader) {
-                    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-                }
-            }
+            checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
         }
+
+        return getProxyClass0(loader, interfaces);
     }
 
     /*
-     * Generate a proxy class (caller-sensitive).
+     * Check permissions required to create a Proxy class.
      *
      * To define a proxy class, it performs the access checks as in
      * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
@@ -446,17 +441,28 @@
      * will throw IllegalAccessError when the generated proxy class is
      * being defined via the defineClass0 method.
      */
-    private static Class<?> getProxyClass0(ClassLoader loader,
-                                           Class<?>... interfaces) {
+    private static void checkProxyAccess(Class<?> caller,
+                                         ClassLoader loader,
+                                         Class<?>... interfaces)
+    {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller
-            final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
-            final ClassLoader ccl = caller.getClassLoader();
-            checkProxyLoader(ccl, loader);
+            ClassLoader ccl = caller.getClassLoader();
+            if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
+                if (!ProxyAccessHelper.allowNullLoader) {
+                    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+                }
+            }
             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
         }
+    }
 
+    /**
+     * Generate a proxy class.  Must call the checkProxyAccess method
+     * to perform permission checks before calling this.
+     */
+    private static Class<?> getProxyClass0(ClassLoader loader,
+                                           Class<?>... interfaces) {
         if (interfaces.length > 65535) {
             throw new IllegalArgumentException("interface limit exceeded");
         }
@@ -698,6 +704,7 @@
      *          if the invocation handler, {@code h}, is
      *          {@code null}
      */
+    @CallerSensitive
     public static Object newProxyInstance(ClassLoader loader,
                                           Class<?>[] interfaces,
                                           InvocationHandler h)
@@ -707,10 +714,15 @@
             throw new NullPointerException();
         }
 
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
+        }
+
         /*
          * Look up or generate the designated proxy class.
          */
-        Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
+        Class<?> cl = getProxyClass0(loader, interfaces);
 
         /*
          * Invoke its constructor with the designated invocation handler.
@@ -718,7 +730,6 @@
         try {
             final Constructor<?> cons = cl.getConstructor(constructorParams);
             final InvocationHandler ih = h;
-            SecurityManager sm = System.getSecurityManager();
             if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                 // create proxy instance with doPrivilege as the proxy class may
                 // implement non-public interfaces that requires a special permission
--- a/jdk/src/share/classes/java/security/AccessController.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/security/AccessController.java	Tue Apr 16 21:39:52 2013 -0700
@@ -26,6 +26,8 @@
 package java.security;
 
 import sun.security.util.Debug;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * <p> The AccessController class is used for access control operations
@@ -264,6 +266,7 @@
      * @see java.security.DomainCombiner
      */
 
+    @CallerSensitive
     public static native <T> T doPrivileged(PrivilegedAction<T> action);
 
     /**
@@ -288,14 +291,15 @@
      *
      * @since 1.6
      */
+    @CallerSensitive
     public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
-
         AccessControlContext acc = getStackAccessControlContext();
         if (acc == null) {
             return AccessController.doPrivileged(action);
         }
         DomainCombiner dc = acc.getAssignedCombiner();
-        return AccessController.doPrivileged(action, preserveCombiner(dc));
+        return AccessController.doPrivileged(action,
+                                             preserveCombiner(dc, Reflection.getCallerClass()));
     }
 
 
@@ -326,6 +330,7 @@
      * @see #doPrivileged(PrivilegedAction)
      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
      */
+    @CallerSensitive
     public static native <T> T doPrivileged(PrivilegedAction<T> action,
                                             AccessControlContext context);
 
@@ -353,6 +358,7 @@
      * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
      * @see java.security.DomainCombiner
      */
+    @CallerSensitive
     public static native <T> T
         doPrivileged(PrivilegedExceptionAction<T> action)
         throws PrivilegedActionException;
@@ -383,34 +389,29 @@
      *
      * @since 1.6
      */
-    public static <T> T doPrivilegedWithCombiner
-        (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
-
+    @CallerSensitive
+    public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action)
+        throws PrivilegedActionException
+    {
         AccessControlContext acc = getStackAccessControlContext();
         if (acc == null) {
             return AccessController.doPrivileged(action);
         }
         DomainCombiner dc = acc.getAssignedCombiner();
-        return AccessController.doPrivileged(action, preserveCombiner(dc));
+        return AccessController.doPrivileged(action,
+                                             preserveCombiner(dc, Reflection.getCallerClass()));
     }
 
     /**
      * preserve the combiner across the doPrivileged call
      */
-    private static AccessControlContext preserveCombiner
-                                        (DomainCombiner combiner) {
-
-        /**
-         * callerClass[0] = Reflection.getCallerClass
-         * callerClass[1] = AccessController.preserveCombiner
-         * callerClass[2] = AccessController.doPrivileged
-         * callerClass[3] = caller
-         */
-        final Class<?> callerClass = sun.reflect.Reflection.getCallerClass(3);
+    private static AccessControlContext preserveCombiner(DomainCombiner combiner,
+                                                         Class<?> caller)
+    {
         ProtectionDomain callerPd = doPrivileged
             (new PrivilegedAction<ProtectionDomain>() {
             public ProtectionDomain run() {
-                return callerClass.getProtectionDomain();
+                return caller.getProtectionDomain();
             }
         });
 
@@ -455,6 +456,7 @@
      * @see #doPrivileged(PrivilegedAction)
      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
      */
+    @CallerSensitive
     public static native <T> T
         doPrivileged(PrivilegedExceptionAction<T> action,
                      AccessControlContext context)
--- a/jdk/src/share/classes/java/sql/DriverManager.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/sql/DriverManager.java	Tue Apr 16 21:39:52 2013 -0700
@@ -30,6 +30,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.concurrent.CopyOnWriteArrayList;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 
 
@@ -192,14 +193,11 @@
      * has been exceeded and has at least tried to cancel the
      * current database connection attempt
      */
+    @CallerSensitive
     public static Connection getConnection(String url,
         java.util.Properties info) throws SQLException {
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
-        return (getConnection(url, info, callerCL));
+        return (getConnection(url, info, Reflection.getCallerClass()));
     }
 
     /**
@@ -226,14 +224,11 @@
      * has been exceeded and has at least tried to cancel the
      * current database connection attempt
      */
+    @CallerSensitive
     public static Connection getConnection(String url,
         String user, String password) throws SQLException {
         java.util.Properties info = new java.util.Properties();
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
         if (user != null) {
             info.put("user", user);
         }
@@ -241,7 +236,7 @@
             info.put("password", password);
         }
 
-        return (getConnection(url, info, callerCL));
+        return (getConnection(url, info, Reflection.getCallerClass()));
     }
 
     /**
@@ -259,16 +254,12 @@
      * has been exceeded and has at least tried to cancel the
      * current database connection attempt
      */
+    @CallerSensitive
     public static Connection getConnection(String url)
         throws SQLException {
 
         java.util.Properties info = new java.util.Properties();
-
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
-        return (getConnection(url, info, callerCL));
+        return (getConnection(url, info, Reflection.getCallerClass()));
     }
 
     /**
@@ -282,21 +273,20 @@
      * that can connect to the given URL
      * @exception SQLException if a database access error occurs
      */
+    @CallerSensitive
     public static Driver getDriver(String url)
         throws SQLException {
 
         println("DriverManager.getDriver(\"" + url + "\")");
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
+        Class<?> callerClass = Reflection.getCallerClass();
 
         // Walk through the loaded registeredDrivers attempting to locate someone
         // who understands the given URL.
         for (DriverInfo aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if(isDriverAllowed(aDriver.driver, callerCL)) {
+            if(isDriverAllowed(aDriver.driver, callerClass)) {
                 try {
                     if(aDriver.driver.acceptsURL(url)) {
                         // Success!
@@ -350,20 +340,18 @@
      * @param driver the JDBC Driver to drop
      * @exception SQLException if a database access error occurs
      */
+    @CallerSensitive
     public static synchronized void deregisterDriver(Driver driver)
         throws SQLException {
         if (driver == null) {
             return;
         }
 
-        // Gets the classloader of the code that called this method,
-        // may be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
         println("DriverManager.deregisterDriver: " + driver);
 
         DriverInfo aDriver = new DriverInfo(driver);
         if(registeredDrivers.contains(aDriver)) {
-            if (isDriverAllowed(driver, callerCL)) {
+            if (isDriverAllowed(driver, Reflection.getCallerClass())) {
                  registeredDrivers.remove(aDriver);
             } else {
                 // If the caller does not have permission to load the driver then
@@ -384,18 +372,17 @@
      *
      * @return the list of JDBC Drivers loaded by the caller's class loader
      */
+    @CallerSensitive
     public static java.util.Enumeration<Driver> getDrivers() {
         java.util.Vector<Driver> result = new java.util.Vector<>();
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
+        Class<?> callerClass = Reflection.getCallerClass();
 
         // Walk through the loaded registeredDrivers.
         for(DriverInfo aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if(isDriverAllowed(aDriver.driver, callerCL)) {
+            if(isDriverAllowed(aDriver.driver, callerClass)) {
                 result.addElement(aDriver.driver);
             } else {
                 println("    skipping: " + aDriver.getClass().getName());
@@ -493,17 +480,13 @@
 
     //------------------------------------------------------------------------
 
-    // Internal method used to get the caller's class loader.
-    // Replaces the call to the native method
-    private static ClassLoader getCallerClassLoader() {
-        Class<?> cc = Reflection.getCallerClass(3);
-        ClassLoader cl = (cc != null) ? cc.getClassLoader() : null;
-        return cl;
+    // Indicates whether the class object that would be created if the code calling
+    // DriverManager is accessible.
+    private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
+        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
+        return isDriverAllowed(driver, callerCL);
     }
 
-
-    // Indicates whether the class object that would be created if the code calling
-    // DriverManager is accessible.
     private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
         boolean result = false;
         if(driver != null) {
@@ -586,18 +569,19 @@
 
     //  Worker method called by the public getConnection() methods.
     private static Connection getConnection(
-        String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
+        String url, java.util.Properties info, Class<?> caller) throws SQLException {
         /*
          * When callerCl is null, we should check the application's
          * (which is invoking this class indirectly)
          * classloader, so that the JDBC driver class outside rt.jar
          * can be loaded from here.
          */
+        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
         synchronized(DriverManager.class) {
-          // synchronize loading of the correct classloader.
-          if(callerCL == null) {
-              callerCL = Thread.currentThread().getContextClassLoader();
-           }
+            // synchronize loading of the correct classloader.
+            if (callerCL == null) {
+                callerCL = Thread.currentThread().getContextClassLoader();
+            }
         }
 
         if(url == null) {
--- a/jdk/src/share/classes/java/util/ResourceBundle.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/util/ResourceBundle.java	Tue Apr 16 21:39:52 2013 -0700
@@ -57,6 +57,8 @@
 import java.util.jar.JarEntry;
 import java.util.spi.ResourceBundleControlProvider;
 
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
 
@@ -440,14 +442,10 @@
 
     /*
      * Automatic determination of the ClassLoader to be used to load
-     * resources on behalf of the client.  N.B. The client is getLoader's
-     * caller's caller.
+     * resources on behalf of the client.
      */
-    private static ClassLoader getLoader() {
-        Class<?>[] stack = getClassContext();
-        /* Magic number 2 identifies our caller's caller */
-        Class<?> c = stack[2];
-        ClassLoader cl = (c == null) ? null : c.getClassLoader();
+    private static ClassLoader getLoader(Class<?> caller) {
+        ClassLoader cl = caller == null ? null : caller.getClassLoader();
         if (cl == null) {
             // When the caller's loader is the boot class loader, cl is null
             // here. In that case, ClassLoader.getSystemClassLoader() may
@@ -461,8 +459,6 @@
         return cl;
     }
 
-    private static native Class<?>[] getClassContext();
-
     /**
      * A wrapper of ClassLoader.getSystemClassLoader().
      */
@@ -746,11 +742,11 @@
      *     if no resource bundle for the specified base name can be found
      * @return a resource bundle for the given base name and the default locale
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName)
     {
         return getBundleImpl(baseName, Locale.getDefault(),
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              getDefaultControl(baseName));
     }
 
@@ -788,11 +784,11 @@
      *        needed.
      * @since 1.6
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName,
                                                  Control control) {
         return getBundleImpl(baseName, Locale.getDefault(),
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              control);
     }
 
@@ -817,12 +813,12 @@
      *        if no resource bundle for the specified base name can be found
      * @return a resource bundle for the given base name and locale
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName,
                                                  Locale locale)
     {
         return getBundleImpl(baseName, locale,
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              getDefaultControl(baseName));
     }
 
@@ -863,11 +859,11 @@
      *        needed.
      * @since 1.6
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
                                                  Control control) {
         return getBundleImpl(baseName, targetLocale,
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              control);
     }
 
@@ -1721,8 +1717,9 @@
      * @since 1.6
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
      */
+    @CallerSensitive
     public static final void clearCache() {
-        clearCache(getLoader());
+        clearCache(getLoader(Reflection.getCallerClass()));
     }
 
     /**
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Tue Apr 16 21:39:52 2013 -0700
@@ -37,6 +37,9 @@
 import java.util.function.IntUnaryOperator;
 import java.util.function.IntBinaryOperator;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
@@ -77,8 +80,9 @@
      * or the field is inaccessible to the caller according to Java language
      * access control
      */
+    @CallerSensitive
     public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
-        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
+        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
     }
 
     /**
@@ -365,9 +369,11 @@
         private final Class<T> tclass;
         private final Class<?> cclass;
 
-        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) {
+        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
+                                      final String fieldName,
+                                      final Class<?> caller)
+        {
             final Field field;
-            final Class<?> caller;
             final int modifiers;
             try {
                 field = AccessController.doPrivileged(
@@ -376,7 +382,6 @@
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Tue Apr 16 21:39:52 2013 -0700
@@ -37,6 +37,9 @@
 import java.util.function.LongUnaryOperator;
 import java.util.function.LongBinaryOperator;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
@@ -77,11 +80,13 @@
      * or the field is inaccessible to the caller according to Java language
      * access control
      */
+    @CallerSensitive
     public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
+        Class<?> caller = Reflection.getCallerClass();
         if (AtomicLong.VM_SUPPORTS_LONG_CAS)
-            return new CASUpdater<U>(tclass, fieldName);
+            return new CASUpdater<U>(tclass, fieldName, caller);
         else
-            return new LockedUpdater<U>(tclass, fieldName);
+            return new LockedUpdater<U>(tclass, fieldName, caller);
     }
 
     /**
@@ -365,9 +370,8 @@
         private final Class<T> tclass;
         private final Class<?> cclass;
 
-        CASUpdater(final Class<T> tclass, final String fieldName) {
+        CASUpdater(final Class<T> tclass, final String fieldName, final Class<?> caller) {
             final Field field;
-            final Class<?> caller;
             final int modifiers;
             try {
                 field = AccessController.doPrivileged(
@@ -376,7 +380,6 @@
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
@@ -490,9 +493,8 @@
         private final Class<T> tclass;
         private final Class<?> cclass;
 
-        LockedUpdater(final Class<T> tclass, final String fieldName) {
+        LockedUpdater(final Class<T> tclass, final String fieldName, final Class<?> caller) {
             Field field = null;
-            Class<?> caller = null;
             int modifiers = 0;
             try {
                 field = AccessController.doPrivileged(
@@ -501,7 +503,6 @@
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Tue Apr 16 21:39:52 2013 -0700
@@ -37,6 +37,9 @@
 import java.util.function.UnaryOperator;
 import java.util.function.BinaryOperator;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
@@ -96,10 +99,12 @@
      * or the field is inaccessible to the caller according to Java language
      * access control
      */
+    @CallerSensitive
     public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
         return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
                                                         vclass,
-                                                        fieldName);
+                                                        fieldName,
+                                                        Reflection.getCallerClass());
     }
 
     /**
@@ -297,10 +302,11 @@
 
         AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
                                         Class<V> vclass,
-                                        final String fieldName) {
+                                        final String fieldName,
+                                        final Class<?> caller)
+        {
             final Field field;
             final Class<?> fieldClass;
-            final Class<?> caller;
             final int modifiers;
             try {
                 field = AccessController.doPrivileged(
@@ -309,7 +315,6 @@
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
--- a/jdk/src/share/classes/java/util/logging/Logger.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/java/util/logging/Logger.java	Tue Apr 16 21:39:52 2013 -0700
@@ -36,6 +36,8 @@
 import java.util.ResourceBundle;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Supplier;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * A Logger object is used to log messages for a specific
@@ -333,13 +335,10 @@
         }
     }
 
-    private static Logger demandLogger(String name, String resourceBundleName) {
+    private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
         LogManager manager = LogManager.getLogManager();
         SecurityManager sm = System.getSecurityManager();
         if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
-            // 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller
-            final int SKIP_FRAMES = 3;
-            Class<?> caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES);
             if (caller.getClassLoader() == null) {
                 return manager.demandSystemLogger(name, resourceBundleName);
             }
@@ -377,6 +376,7 @@
 
     // Synchronization is not required here. All synchronization for
     // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
     public static Logger getLogger(String name) {
         // This method is intentionally not a wrapper around a call
         // to getLogger(name, resourceBundleName). If it were then
@@ -388,7 +388,7 @@
         // would throw an IllegalArgumentException in the second call
         // because the wrapper would result in an attempt to replace
         // the existing "resourceBundleForFoo" with null.
-        return demandLogger(name, null);
+        return demandLogger(name, null, Reflection.getCallerClass());
     }
 
     /**
@@ -434,8 +434,9 @@
 
     // Synchronization is not required here. All synchronization for
     // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
     public static Logger getLogger(String name, String resourceBundleName) {
-        Logger result = demandLogger(name, resourceBundleName);
+        Logger result = demandLogger(name, resourceBundleName, Reflection.getCallerClass());
 
         // MissingResourceException or IllegalArgumentException can be
         // thrown by setupResourceInfo().
--- a/jdk/src/share/classes/javax/script/ScriptEngineManager.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/javax/script/ScriptEngineManager.java	Tue Apr 16 21:39:52 2013 -0700
@@ -28,6 +28,7 @@
 import java.security.*;
 import java.util.ServiceLoader;
 import java.util.ServiceConfigurationError;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
@@ -60,9 +61,10 @@
      *
      * @see java.lang.Thread#getContextClassLoader
      */
+    @CallerSensitive
     public ScriptEngineManager() {
         ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
-        if (canCallerAccessLoader(ctxtLoader)) {
+        if (canCallerAccessLoader(ctxtLoader, Reflection.getCallerClass())) {
             if (DEBUG) System.out.println("using " + ctxtLoader);
             init(ctxtLoader);
         } else {
@@ -419,10 +421,10 @@
     /** Global bindings associated with script engines created by this manager. */
     private Bindings globalScope;
 
-    private boolean canCallerAccessLoader(ClassLoader loader) {
+    private boolean canCallerAccessLoader(ClassLoader loader, Class<?> caller) {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader callerLoader = getCallerClassLoader();
+            ClassLoader callerLoader = getClassLoader(caller);
             if (!sun.misc.VM.isSystemDomainLoader(callerLoader)) {
                 if (loader != callerLoader || !isAncestor(loader, callerLoader)) {
                     try {
@@ -438,10 +440,9 @@
         return true;
     }
 
-    // Note that this code is same as ClassLoader.getCallerClassLoader().
+    // Note that this code is same as ClassLoader.getClassLoader().
     // But, that method is package private and hence we can't call here.
-    private ClassLoader getCallerClassLoader() {
-        Class<?> caller = Reflection.getCallerClass(3);
+    private ClassLoader getClassLoader(Class<?> caller) {
         if (caller == null) {
             return null;
         }
--- a/jdk/src/share/classes/sun/misc/Unsafe.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/sun/misc/Unsafe.java	Tue Apr 16 21:39:52 2013 -0700
@@ -28,6 +28,9 @@
 import java.security.*;
 import java.lang.reflect.*;
 
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 
 /**
  * A collection of methods for performing low-level, unsafe operations.
@@ -80,9 +83,10 @@
      *             <code>checkPropertiesAccess</code> method doesn't allow
      *             access to the system properties.
      */
+    @CallerSensitive
     public static Unsafe getUnsafe() {
-        Class<?> cc = sun.reflect.Reflection.getCallerClass(2);
-        if (!VM.isSystemDomainLoader(cc.getClassLoader()))
+        Class<?> caller = Reflection.getCallerClass();
+        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
             throw new SecurityException("Unsafe");
         return theUnsafe;
     }
@@ -817,8 +821,6 @@
                                        ClassLoader loader,
                                        ProtectionDomain protectionDomain);
 
-    public native Class<?> defineClass(String name, byte[] b, int off, int len);
-
     /**
      * Define a class but do not make it known to the class loader or system dictionary.
      * <p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/reflect/CallerSensitive.java	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.reflect;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+/**
+ * A method annotated @CallerSensitive is sensitive to its calling class,
+ * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
+ * or via some equivalent.
+ *
+ * @author John R. Rose
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({CONSTRUCTOR, METHOD})
+public @interface CallerSensitive {
+}
--- a/jdk/src/share/classes/sun/reflect/Reflection.java	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/classes/sun/reflect/Reflection.java	Tue Apr 16 21:39:52 2013 -0700
@@ -51,16 +51,11 @@
         methodFilterMap = new HashMap<>();
     }
 
-    /** Returns the class of the method <code>realFramesToSkip</code>
-        frames up the stack (zero-based), ignoring frames associated
-        with java.lang.reflect.Method.invoke() and its implementation.
-        The first frame is that associated with this method, so
-        <code>getCallerClass(0)</code> returns the Class object for
-        sun.reflect.Reflection. Frames associated with
-        java.lang.reflect.Method.invoke() and its implementation are
-        completely ignored and do not count toward the number of "real"
-        frames skipped. */
-    public static native Class<?> getCallerClass(int realFramesToSkip);
+    /** Returns the class of the caller of the method calling this method,
+        ignoring frames associated with java.lang.reflect.Method.invoke()
+        and its implementation. */
+    @CallerSensitive
+    public static native Class<?> getCallerClass();
 
     /** Retrieves the access flags written to the class file. For
         inner classes these flags may differ from those returned by
@@ -321,4 +316,27 @@
         }
         return newMembers;
     }
+
+    /**
+     * Tests if the given method is caller-sensitive and the declaring class
+     * is defined by either the bootstrap class loader or extension class loader.
+     */
+    public static boolean isCallerSensitive(Method m) {
+        final ClassLoader loader = m.getDeclaringClass().getClassLoader();
+        if (sun.misc.VM.isSystemDomainLoader(loader) || isExtClassLoader(loader))  {
+            return m.isAnnotationPresent(CallerSensitive.class);
+        }
+        return false;
+    }
+
+    private static boolean isExtClassLoader(ClassLoader loader) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        while (cl != null) {
+            if (cl.getParent() == null && cl == loader) {
+                return true;
+            }
+            cl = cl.getParent();
+        }
+        return false;
+    }
 }
--- a/jdk/src/share/javavm/export/jvm.h	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/javavm/export/jvm.h	Tue Apr 16 21:39:52 2013 -0700
@@ -350,16 +350,21 @@
 /*
  * java.lang.Class and java.lang.ClassLoader
  */
+
+#define JVM_DEPTH -1
+
 /*
- * Returns the class in which the code invoking the native method
- * belongs.
+ * Returns the immediate caller class of the native method invoking
+ * JVM_GetCallerClass.  The Method.invoke and other frames due to
+ * reflection machinery are skipped.
  *
- * Note that in JDK 1.1, native methods did not create a frame.
- * In 1.2, they do. Therefore native methods like Class.forName
- * can no longer look at the current frame for the caller class.
+ * The depth parameter must be -1 (JVM_DEPTH). The caller is expected
+ * to be marked with sun.reflect.CallerSensitive.  The JVM will throw
+ * an error if it is not marked propertly.
  */
 JNIEXPORT jclass JNICALL
-JVM_GetCallerClass(JNIEnv *env, int n);
+JVM_GetCallerClass(JNIEnv *env, int depth);
+
 
 /*
  * Find primitive classes
--- a/jdk/src/share/native/java/lang/ClassLoader.c	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/native/java/lang/ClassLoader.c	Tue Apr 16 21:39:52 2013 -0700
@@ -492,24 +492,6 @@
     (*env)->ReleaseStringUTFChars(env, name, cname);
     return res;
 }
-
-JNIEXPORT jobject JNICALL
-Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index)
-{
-    jobjectArray jcallerStack;
-    int len;
-
-    jcallerStack = JVM_GetClassContext(env);
-    if ((*env)->ExceptionCheck(env)) {
-        return NULL;
-    }
-    len = (*env)->GetArrayLength(env, jcallerStack);
-    if (index < len) {
-        return (*env)->GetObjectArrayElement(env, jcallerStack, index);
-    }
-    return NULL;
-}
-
 /*
  * Class:     java_lang_ClassLoader_NativeLibrary
  * Method:    findBuiltinLib
--- a/jdk/src/share/native/java/lang/ResourceBundle.c	Wed Apr 17 10:15:33 2013 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jvm.h"
-
-#include "java_util_ResourceBundle.h"
-
-JNIEXPORT jobjectArray JNICALL
-Java_java_util_ResourceBundle_getClassContext(JNIEnv *env, jobject this)
-{
-    return JVM_GetClassContext(env);
-}
--- a/jdk/src/share/native/java/lang/SecurityManager.c	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/native/java/lang/SecurityManager.c	Tue Apr 16 21:39:52 2013 -0700
@@ -29,7 +29,6 @@
 
 #include "java_lang_SecurityManager.h"
 #include "java_lang_ClassLoader.h"
-#include "java_util_ResourceBundle.h"
 
 /*
  * Make sure a security manager instance is initialized.
--- a/jdk/src/share/native/sun/reflect/Reflection.c	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/src/share/native/sun/reflect/Reflection.c	Tue Apr 16 21:39:52 2013 -0700
@@ -27,9 +27,9 @@
 #include "sun_reflect_Reflection.h"
 
 JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass
-(JNIEnv *env, jclass unused, jint depth)
+(JNIEnv *env, jclass unused)
 {
-    return JVM_GetCallerClass(env, depth);
+    return JVM_GetCallerClass(env, JVM_DEPTH); // JVM_DEPTH is only the expected value
 }
 
 JNIEXPORT jint JNICALL Java_sun_reflect_Reflection_getClassAccessFlags
--- a/jdk/test/Makefile	Wed Apr 17 10:15:33 2013 +0800
+++ b/jdk/test/Makefile	Tue Apr 16 21:39:52 2013 -0700
@@ -478,7 +478,7 @@
 # Stable agentvm testruns (minus items from PROBLEM_LIST)
 JDK_ALL_TARGETS += jdk_lang
 JDK_DEFAULT_TARGETS += jdk_lang
-jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc vm)
+jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc sun/reflect vm)
 	$(call RunAgentvmBatch)
 
 # Stable othervm testruns (minus items from PROBLEM_LIST)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.jdeps.ClassFileReader;
+import static com.sun.tools.classfile.ConstantPool.*;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+
+/*
+ * @test
+ * @bug 8010117
+ * @summary Verify if CallerSensitive methods are annotated with
+ *          sun.reflect.CallerSensitive annotation
+ * @build CallerSensitiveFinder MethodFinder
+ * @run main/othervm/timeout=900 -mx600m CallerSensitiveFinder
+ */
+public class CallerSensitiveFinder extends MethodFinder {
+    private static int numThreads = 3;
+    private static boolean verbose = false;
+    public static void main(String[] args) throws Exception {
+        List<Path> classes = new ArrayList<>();
+        String testclasses = System.getProperty("test.classes", ".");
+        int i = 0;
+        while (i < args.length) {
+            String arg = args[i++];
+            if (arg.equals("-v")) {
+                verbose = true;
+            } else {
+                Path p = Paths.get(testclasses, arg);
+                if (!p.toFile().exists()) {
+                    throw new IllegalArgumentException(arg + " does not exist");
+                }
+                classes.add(p);
+            }
+        }
+        if (classes.isEmpty()) {
+            classes.addAll(PlatformClassPath.getJREClasses());
+        }
+        final String method = "sun/reflect/Reflection.getCallerClass";
+        CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method);
+
+        List<String> errors = csfinder.run(classes);
+        if (!errors.isEmpty()) {
+            throw new RuntimeException(errors.size() +
+                    " caller-sensitive methods are missing @CallerSensitive annotation");
+        }
+    }
+
+    private final List<String> csMethodsMissingAnnotation = new ArrayList<>();
+    public CallerSensitiveFinder(String... methods) {
+        super(methods);
+    }
+
+    public List<String> run(List<Path> classes) throws IOException, InterruptedException,
+            ExecutionException, ConstantPoolException
+    {
+        ExecutorService pool = Executors.newFixedThreadPool(numThreads);
+        for (Path path : classes) {
+            ClassFileReader reader = ClassFileReader.newInstance(path.toFile());
+            for (ClassFile cf : reader.getClassFiles()) {
+                String classFileName = cf.getName();
+                // for each ClassFile
+                //    parse constant pool to find matching method refs
+                //      parse each method (caller)
+                //      - visit and find method references matching the given method name
+                pool.submit(getTask(cf));
+            }
+        }
+        waitForCompletion();
+        pool.shutdown();
+        return csMethodsMissingAnnotation;
+    }
+
+    private static final String CALLER_SENSITIVE_ANNOTATION = "Lsun/reflect/CallerSensitive;";
+    private static boolean isCallerSensitive(Method m, ConstantPool cp)
+            throws ConstantPoolException
+    {
+        RuntimeAnnotations_attribute attr =
+            (RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations);
+        int index = 0;
+        if (attr != null) {
+            for (int i = 0; i < attr.annotations.length; i++) {
+                Annotation ann = attr.annotations[i];
+                String annType = cp.getUTF8Value(ann.type_index);
+                if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void referenceFound(ClassFile cf, Method m, Set<Integer> refs)
+            throws ConstantPoolException
+    {
+        String name = String.format("%s#%s %s", cf.getName(),
+                                    m.getName(cf.constant_pool),
+                                    m.descriptor.getValue(cf.constant_pool));
+        if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) {
+            csMethodsMissingAnnotation.add(name);
+            System.err.println("Missing @CallerSensitive: " + name);
+        } else {
+            if (verbose) {
+                System.out.format("@CS  %s%n", name);
+            }
+        }
+    }
+
+    private final List<FutureTask<String>> tasks = new ArrayList<FutureTask<String>>();
+    private FutureTask<String> getTask(final ClassFile cf) {
+        FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
+            public String call() throws Exception {
+                return parse(cf);
+            }
+        });
+        tasks.add(task);
+        return task;
+    }
+
+    private void waitForCompletion() throws InterruptedException, ExecutionException {
+        for (FutureTask<String> t : tasks) {
+            String s = t.get();
+        }
+        System.out.println("Parsed " + tasks.size() + " classfiles");
+    }
+
+    static class PlatformClassPath {
+        static List<Path> getJREClasses() throws IOException {
+            List<Path> result = new ArrayList<Path>();
+            Path home = Paths.get(System.getProperty("java.home"));
+
+            if (home.endsWith("jre")) {
+                // jar files in <javahome>/jre/lib
+                // skip <javahome>/lib
+                result.addAll(addJarFiles(home.resolve("lib")));
+            } else if (home.resolve("lib").toFile().exists()) {
+                // either a JRE or a jdk build image
+                File classes = home.resolve("classes").toFile();
+                if (classes.exists() && classes.isDirectory()) {
+                    // jdk build outputdir
+                    result.add(classes.toPath());
+                }
+                // add other JAR files
+                result.addAll(addJarFiles(home.resolve("lib")));
+            } else {
+                throw new RuntimeException("\"" + home + "\" not a JDK home");
+            }
+            return result;
+        }
+
+        static List<Path> addJarFiles(final Path root) throws IOException {
+            final List<Path> result = new ArrayList<Path>();
+            final Path ext = root.resolve("ext");
+            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+                        throws IOException {
+                    if (dir.equals(root) || dir.equals(ext)) {
+                        return FileVisitResult.CONTINUE;
+                    } else {
+                        // skip other cobundled JAR files
+                        return FileVisitResult.SKIP_SUBTREE;
+                    }
+                }
+
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                        throws IOException {
+                    File f = file.toFile();
+                    String fn = f.getName();
+                    // parse alt-rt.jar as well
+                    if (fn.endsWith(".jar") && !fn.equals("jfxrt.jar")) {
+                        result.add(file);
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+            return result;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.*;
+import com.sun.tools.classfile.*;
+import static com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.Instruction.TypeKind;
+
+/**
+ * MethodFinder utility class to find references to the given methods.
+ */
+public abstract class MethodFinder {
+    final List<String> methods;
+    public MethodFinder(String... methods) {
+        this.methods = Arrays.asList(methods);
+    }
+
+    /**
+     * A callback method will be invoked when a method referencing
+     * any of the lookup methods.
+     *
+     * @param cf ClassFile
+     * @param m Method
+     * @param refs Set of constant pool indices that reference the methods
+     *             matching the given lookup method names
+     */
+    public abstract void referenceFound(ClassFile cf, Method m, Set<Integer> refs)
+            throws ConstantPoolException;
+
+    public String parse(ClassFile cf) throws ConstantPoolException {
+        List<Integer> cprefs = new ArrayList<Integer>();
+        int index = 1;
+        for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) {
+            if (cpInfo.accept(cpVisitor, null)) {
+                cprefs.add(index);
+            }
+            index += cpInfo.size();
+        }
+
+        if (!cprefs.isEmpty()) {
+            for (Method m : cf.methods) {
+                Set<Integer> refs = new HashSet<Integer>();
+                Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code);
+                if (c_attr != null) {
+                    for (Instruction instr : c_attr.getInstructions()) {
+                        int idx = instr.accept(codeVisitor, cprefs);
+                        if (idx > 0) {
+                            refs.add(idx);
+                        }
+                    }
+                }
+                if (refs.size() > 0) {
+                    referenceFound(cf, m, refs);
+                }
+            }
+        }
+        return cprefs.isEmpty() ? "" : cf.getName();
+    }
+
+    private ConstantPool.Visitor<Boolean,Void> cpVisitor =
+            new ConstantPool.Visitor<Boolean,Void>()
+    {
+        private boolean matches(CPRefInfo info) {
+            try {
+                CONSTANT_NameAndType_info nat = info.getNameAndTypeInfo();
+                return matches(info.getClassName(), nat.getName(), nat.getType());
+            } catch (ConstantPoolException ex) {
+                return false;
+            }
+        }
+
+        private boolean matches(String cn, String name, String type) {
+            return methods.contains(cn + "." + name);
+        }
+
+        public Boolean visitClass(CONSTANT_Class_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
+            return matches(info);
+        }
+
+        public Boolean visitMethodref(CONSTANT_Methodref_info info, Void p) {
+            return matches(info);
+        }
+
+        public Boolean visitDouble(CONSTANT_Double_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitFieldref(CONSTANT_Fieldref_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitFloat(CONSTANT_Float_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitInteger(CONSTANT_Integer_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitLong(CONSTANT_Long_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitMethodType(CONSTANT_MethodType_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitString(CONSTANT_String_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitUtf8(CONSTANT_Utf8_info info, Void p) {
+            return false;
+        }
+    };
+
+    private Instruction.KindVisitor<Integer, List<Integer>> codeVisitor =
+            new Instruction.KindVisitor<Integer, List<Integer>>()
+    {
+        public Integer visitNoOperands(Instruction instr, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitArrayType(Instruction instr, TypeKind kind, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitBranch(Instruction instr, int offset, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitConstantPoolRef(Instruction instr, int index, List<Integer> p) {
+            return p.contains(index) ? index : 0;
+        }
+
+        public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List<Integer> p) {
+            return p.contains(index) ? index : 0;
+        }
+
+        public Integer visitLocal(Instruction instr, int index, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitLocalAndValue(Instruction instr, int index, int value, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitValue(Instruction instr, int value, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitUnknown(Instruction instr, List<Integer> p) {
+            return 0;
+        }
+    };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * @test
+ * @bug 8010117
+ * @summary Test CallerSensitiveFinder to find missing annotation
+ * @compile -XDignore.symbol.file MissingCallerSensitive.java
+ * @build CallerSensitiveFinder MethodFinder
+ * @run main MissingCallerSensitive
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+public class MissingCallerSensitive {
+    public static void main(String[] args) throws Exception {
+        String testclasses = System.getProperty("test.classes", ".");
+        List<Path> classes = new ArrayList<>();
+        classes.add(Paths.get(testclasses, "MissingCallerSensitive.class"));
+
+        final String method = "sun/reflect/Reflection.getCallerClass";
+        CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method);
+        List<String> errors = csfinder.run(classes);
+        if (errors.size() != 1) {
+            throw new RuntimeException("Unexpected number of methods found: " + errors.size());
+        }
+        String m = errors.get(0);
+        if (!m.startsWith("MissingCallerSensitive#missingCallerSensitiveAnnotation")) {
+            throw new RuntimeException("Unexpected method missing annotation: " + m);
+        }
+    }
+
+    @sun.reflect.CallerSensitive
+    public ClassLoader getCallerLoader() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+
+    public ClassLoader missingCallerSensitiveAnnotation() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/reflect/Reflection/GetCallerClass.java	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package boot;
+
+public class GetCallerClass {
+    @sun.reflect.CallerSensitive
+    public ClassLoader getCallerLoader() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+
+    public ClassLoader missingCallerSensitiveAnnotation() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.java	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import boot.GetCallerClass;
+import java.lang.reflect.*;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+public class GetCallerClassTest {
+    private final GetCallerClass gcc;   // boot.GetCallerClass is in bootclasspath
+    GetCallerClassTest() {
+        this.gcc = new GetCallerClass();
+    }
+
+    public static void main(String[] args) throws Exception {
+        GetCallerClassTest gcct = new GetCallerClassTest();
+        // ensure methods are annotated with @CallerSensitive
+        ensureAnnotationPresent(boot.GetCallerClass.class, "getCallerLoader", true);
+        ensureAnnotationPresent(GetCallerClassTest.class, "testNonSystemMethod", false);
+        // call Reflection.getCallerClass from bootclasspath with and without @CS
+        gcct.testCallerSensitiveMethods();
+        // call Reflection.getCallerClass from classpath with @CS
+        gcct.testNonSystemMethod();
+    }
+
+    private static void ensureAnnotationPresent(Class<?> c, String name, boolean cs)
+        throws NoSuchMethodException
+    {
+        Method m = c.getDeclaredMethod(name);
+        if (!m.isAnnotationPresent(CallerSensitive.class)) {
+            throw new RuntimeException("@CallerSensitive not present in method " + m);
+        }
+        if (Reflection.isCallerSensitive(m) != cs) {
+            throw new RuntimeException("Unexpected: isCallerSensitive returns " +
+                Reflection.isCallerSensitive(m));
+        }
+    }
+
+    private void testCallerSensitiveMethods() {
+        try {
+            ClassLoader cl = gcc.getCallerLoader();
+            if (cl != GetCallerClassTest.class.getClassLoader()) {
+                throw new RuntimeException("mismatched class loader");
+            }
+            gcc.missingCallerSensitiveAnnotation();
+            throw new RuntimeException("getCallerLoader not marked with @CallerSensitive");
+        } catch (InternalError e) {
+            StackTraceElement[] stackTrace = e.getStackTrace();
+            checkStackTrace(stackTrace, e);
+            if (!stackTrace[1].getClassName().equals(GetCallerClass.class.getName()) ||
+                !stackTrace[1].getMethodName().equals("missingCallerSensitiveAnnotation")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) ||
+                !stackTrace[2].getMethodName().equals("testCallerSensitiveMethods")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            System.out.println("Expected error: " + e.getMessage());
+        }
+    }
+
+    @CallerSensitive
+    private void testNonSystemMethod() {
+        try {
+            Class<?> c = Reflection.getCallerClass();
+            throw new RuntimeException("@CallerSensitive testNonSystemMethods not supported");
+        } catch (InternalError e) {
+            StackTraceElement[] stackTrace = e.getStackTrace();
+            checkStackTrace(stackTrace, e);
+            if (!stackTrace[1].getClassName().equals(GetCallerClassTest.class.getName()) ||
+                !stackTrace[1].getMethodName().equals("testNonSystemMethod")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) ||
+                !stackTrace[2].getMethodName().equals("main")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            System.out.println("Expected error: " + e.getMessage());
+        }
+    }
+
+    private void checkStackTrace(StackTraceElement[] stackTrace, Error e) {
+        if (stackTrace.length < 3) {
+            throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+        }
+
+        if (!stackTrace[0].getClassName().equals("sun.reflect.Reflection") ||
+            !stackTrace[0].getMethodName().equals("getCallerClass")) {
+            throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh	Tue Apr 16 21:39:52 2013 -0700
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8010117
+# @summary Test if the VM enforces sun.reflect.Reflection.getCallerClass 
+#          be called by methods annotated with sun.reflect.CallerSensitive
+#
+# @run shell GetCallerClassTest.sh
+
+if [ "${TESTSRC}" = "" ]
+then
+  echo "TESTSRC not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+echo "TESTSRC=${TESTSRC}"
+if [ "${TESTJAVA}" = "" ]
+then
+  echo "TESTJAVA not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+echo "TESTJAVA=${TESTJAVA}"
+if [ "${COMPILEJAVA}" = "" ]
+then
+  COMPILEJAVA="${TESTJAVA}"
+fi
+echo "COMPILEJAVA=${COMPILEJAVA}"
+if [ "${TESTCLASSES}" = "" ]
+then
+  echo "TESTCLASSES not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+BCP=${TESTCLASSES}/bcp
+rm -rf ${BCP}
+mkdir ${BCP}
+
+# Compile GetCallerClass in bootclasspath
+${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \
+     -XDignore.symbol.file \
+     -d ${BCP} ${TESTSRC}/GetCallerClass.java  || exit 1
+
+${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \
+     -XDignore.symbol.file -Xbootclasspath/a:${BCP} \
+     -d ${TESTCLASSES} ${TESTSRC}/GetCallerClassTest.java  || exit 2
+
+${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:${BCP} \
+     -cp ${TESTCLASSES} GetCallerClassTest || exit 3