--- old/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java 2018-01-30 23:31:18.208354539 -0500 +++ new/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java 2018-01-30 23:31:16.724269815 -0500 @@ -133,7 +133,7 @@ case PRIVATE: // Rules for privates follows access rules for nestmates. return ((allowedModes & PRIVATE) != 0 && - Reflection.areNestMates(defc, lookupClass)); + areNestMates(defc, lookupClass)); default: throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods)); } @@ -336,6 +336,33 @@ return Objects.equals(class1.getPackageName(), class2.getPackageName()); } + /** + * Test if two classes are defined as part of the same package member (top-level class). + * If this is true, they can share private access with each other. + * @param class1 a class + * @param class2 another class + * @return whether they are identical or nested together + */ + public static boolean areNestMates(Class class1, Class class2) { + if (class1 == class2) + return true; + if (!isSamePackage(class1, class2)) + return false; + if (Reflection.areNestMates(class1, class2)) + return true; + // Could be pre-nestmate nested types + if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2)) + return false; + return true; + } + + private static Class getOutermostEnclosingClass(Class c) { + Class pkgmem = c; + for (Class enc = c; (enc = enc.getEnclosingClass()) != null; ) + pkgmem = enc; + return pkgmem; + } + private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2, boolean loader1MustBeParent) { if (loader1 == loader2 || loader1 == null