jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
changeset 36935 9a10a2c4dc13
parent 36934 590fc47a0aeb
parent 36656 a8cad521af47
child 37340 81f996e37e7f
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Mar 24 11:21:21 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Mar 24 16:21:19 2016 +0100
@@ -26,7 +26,13 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyAccess;
@@ -44,6 +50,9 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
 import static java.lang.invoke.MethodHandleImpl.Intrinsic;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
@@ -98,11 +107,11 @@
 
     /**
      * Returns a {@link Lookup lookup object} which is trusted minimally.
-     * It can only be used to create method handles to
-     * publicly accessible fields and methods.
+     * It can only be used to create method handles to public members in
+     * public classes in packages that are exported unconditionally.
      * <p>
-     * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
-     * of this lookup object will be {@link java.lang.Object}.
+     * For now, the {@linkplain Lookup#lookupClass lookup class} of this lookup
+     * object is in an unnamed module.
      * Consequently, the lookup context of this lookup object will be the bootstrap
      * class loader, which means it cannot find user classes.
      *
@@ -110,8 +119,6 @@
      * <em>Discussion:</em>
      * The lookup class can be changed to any other class {@code C} using an expression of the form
      * {@link Lookup#in publicLookup().in(C.class)}.
-     * Since all classes have equal access to public names,
-     * such a change would confer no new access rights,
      * but may change the lookup context by virtue of changing the class loader.
      * A public lookup object is always subject to
      * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
@@ -120,7 +127,15 @@
      * @return a lookup object which is trusted minimally
      */
     public static Lookup publicLookup() {
-        return Lookup.PUBLIC_LOOKUP;
+        // During VM startup then only classes in the java.base module can be
+        // loaded and linked. This is because java.base exports aren't setup until
+        // the module system is initialized, hence types in the unnamed module
+        // (or any named module) can't link to java/lang/Object.
+        if (!jdk.internal.misc.VM.isModuleSystemInited()) {
+            return new Lookup(Object.class, Lookup.PUBLIC);
+        } else {
+            return LookupHelper.PUBLIC_LOOKUP;
+        }
     }
 
     /**
@@ -393,7 +408,7 @@
      * to a subset of members normally accessible to the lookup class.
      * For example, the {@link MethodHandles#publicLookup publicLookup}
      * method produces a lookup object which is only allowed to access
-     * public members in public classes.
+     * public members in public classes of exported packages.
      * The caller sensitive method {@link MethodHandles#lookup lookup}
      * produces a lookup object with full capabilities relative to
      * its caller class, to emulate all supported bytecode behaviors.
@@ -565,12 +580,24 @@
          */
         public static final int PACKAGE = Modifier.STATIC;
 
-        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+        /** A single-bit mask representing {@code module} access (default access),
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value is {@code 0x10}, which does not correspond meaningfully to
+         *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+         *  In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup}
+         *  with this lookup mode can access all public types in the module of the
+         *  lookup class and public types in packages exported by other modules
+         *  to the module of the lookup class.
+         *  @since 9
+         */
+        public static final int MODULE = PACKAGE << 1;
+
+        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE);
         private static final int TRUSTED   = -1;
 
         private static int fixmods(int mods) {
-            mods &= (ALL_MODES - PACKAGE);
-            return (mods != 0) ? mods : PACKAGE;
+            mods &= (ALL_MODES - PACKAGE - MODULE);
+            return (mods != 0) ? mods : (PACKAGE | MODULE);
         }
 
         /** Tells which class is performing the lookup.  It is this class against
@@ -596,11 +623,14 @@
          *  {@linkplain #PUBLIC PUBLIC (0x01)},
          *  {@linkplain #PRIVATE PRIVATE (0x02)},
          *  {@linkplain #PROTECTED PROTECTED (0x04)},
-         *  and {@linkplain #PACKAGE PACKAGE (0x08)}.
+         *  {@linkplain #PACKAGE PACKAGE (0x08)},
+         *  and {@linkplain #MODULE MODULE (0x10)}.
          *  <p>
          *  A freshly-created lookup object
          *  on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
-         *  has all possible bits set, since the caller class can access all its own members.
+         *  has all possible bits set, since the caller class can access all its own members,
+         *  all public types in the caller's module, and all public types in packages exported
+         *  by other modules to the caller's module.
          *  A lookup object on a new lookup class
          *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
          *  may have some mode bits set to zero.
@@ -637,6 +667,12 @@
          * However, the resulting {@code Lookup} object is guaranteed
          * to have no more access capabilities than the original.
          * In particular, access capabilities can be lost as follows:<ul>
+         * <li>If the lookup class for this {@code Lookup} is not in a named module,
+         * and the new lookup class is in a named module {@code M}, then no members in
+         * {@code M}'s non-exported packages will be accessible.
+         * <li>If the lookup for this {@code Lookup} is in a named module, and the
+         * new lookup class is in a different module {@code M}, then no members, not even
+         * public members in {@code M}'s exported packages, will be accessible.
          * <li>If the new lookup class differs from the old one,
          * protected members will not be accessible by virtue of inheritance.
          * (Protected members may continue to be accessible because of package sharing.)
@@ -664,7 +700,17 @@
                 return new Lookup(requestedLookupClass, ALL_MODES);
             if (requestedLookupClass == this.lookupClass)
                 return this;  // keep same capabilities
+
             int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+            if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) {
+                // Allowed to teleport from an unnamed to a named module but resulting
+                // Lookup has no access to module private members
+                if (this.lookupClass.getModule().isNamed()) {
+                    newModes = 0;
+                } else {
+                    newModes &= ~MODULE;
+                }
+            }
             if ((newModes & PACKAGE) != 0
                 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
                 newModes &= ~(PACKAGE|PRIVATE);
@@ -680,6 +726,7 @@
                 // No permissions.
                 newModes = 0;
             }
+
             checkUnprivilegedlookupClass(requestedLookupClass, newModes);
             return new Lookup(requestedLookupClass, newModes);
         }
@@ -687,12 +734,6 @@
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }
 
-        /** Version of lookup which is trusted minimally.
-         *  It can only be used to create method handles to
-         *  publicly accessible members.
-         */
-        static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
-
         /** Package-private version of lookup which is trusted. */
         static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
 
@@ -720,12 +761,13 @@
          * allowed access, and is chosen as follows:
          * <ul>
          * <li>If no access is allowed, the suffix is "/noaccess".
-         * <li>If only public access is allowed, the suffix is "/public".
-         * <li>If only public and package access are allowed, the suffix is "/package".
-         * <li>If only public, package, and private access are allowed, the suffix is "/private".
+         * <li>If only public access to types in exported packages is allowed, the suffix is "/public".
+         * <li>If only public and module access are allowed, the suffix is "/module".
+         * <li>If only public, module and package access are allowed, the suffix is "/package".
+         * <li>If only public, module, package, and private access are allowed, the suffix is "/private".
          * </ul>
          * If none of the above cases apply, it is the case that full
-         * access (public, package, private, and protected) is allowed.
+         * access (public, module, package, private, and protected) is allowed.
          * In this case, no suffix is added.
          * This is true only of an object obtained originally from
          * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
@@ -747,7 +789,9 @@
                 return cname + "/noaccess";
             case PUBLIC:
                 return cname + "/public";
-            case PUBLIC|PACKAGE:
+            case PUBLIC|MODULE:
+                return cname + "/module";
+            case PUBLIC|MODULE|PACKAGE:
                 return cname + "/package";
             case ALL_MODES & ~PROTECTED:
                 return cname + "/private";
@@ -1652,7 +1696,7 @@
             Objects.requireNonNull(refc);
             Class<?> caller = lookupClassOrNull();
             if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
-                throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
+                throw new MemberName(refc).makeAccessException("symbolic reference class is not accessible", this);
         }
 
         /** Check name for an illegal leading "&lt;" character. */
@@ -1781,8 +1825,6 @@
             if (Modifier.isFinal(mods) &&
                     MethodHandleNatives.refKindIsSetter(refKind))
                 throw m.makeAccessException("unexpected set of a final field", this);
-            if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
-                return;  // common case
             int requestedModes = fixmods(mods);  // adjust 0 => PACKAGE
             if ((requestedModes & allowedModes) != 0) {
                 if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
@@ -1812,7 +1854,7 @@
             if (!classOK)
                 return "class is not public";
             if (Modifier.isPublic(mods))
-                return "access to public member failed";  // (how?)
+                return "access to public member failed";  // (how?, module not readable?)
             if (Modifier.isPrivate(mods))
                 return "member is private";
             if (Modifier.isProtected(mods))
@@ -2120,6 +2162,61 @@
     }
 
     /**
+     * Helper class used to lazily create PUBLIC_LOOKUP with a lookup class
+     * in an <em>unnamed module</em>.
+     *
+     * @see Lookup#publicLookup
+     */
+    private static class LookupHelper {
+        private static final String UNNAMED = "Unnamed";
+        private static final String OBJECT  = "java/lang/Object";
+
+        private static Class<?> createClass() {
+            try {
+                ClassWriter cw = new ClassWriter(0);
+                cw.visit(Opcodes.V1_8,
+                         Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
+                         UNNAMED,
+                         null,
+                         OBJECT,
+                         null);
+                cw.visitSource(UNNAMED, null);
+                cw.visitEnd();
+                byte[] bytes = cw.toByteArray();
+                ClassLoader loader = new ClassLoader(null) {
+                    @Override
+                    protected Class<?> findClass(String cn) throws ClassNotFoundException {
+                        if (cn.equals(UNNAMED))
+                            return super.defineClass(UNNAMED, bytes, 0, bytes.length);
+                        throw new ClassNotFoundException(cn);
+                    }
+                };
+                return loader.loadClass(UNNAMED);
+            } catch (Exception e) {
+                throw new InternalError(e);
+            }
+        }
+
+        private static final Class<?> PUBLIC_LOOKUP_CLASS;
+        static {
+            PrivilegedAction<Class<?>> pa = new PrivilegedAction<Class<?>>() {
+                public Class<?> run() {
+                    return createClass();
+                }
+            };
+            PUBLIC_LOOKUP_CLASS = AccessController.doPrivileged(pa);
+        }
+
+        /**
+         * Lookup that is trusted minimally. It can only be used to create
+         * method handles to publicly accessible members in exported packages.
+         *
+         * @see MethodHandles#publicLookup
+         */
+        static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC);
+    }
+
+    /**
      * Produces a method handle giving read access to elements of an array.
      * The type of the method handle will have a return type of the array's
      * element type.  Its first argument will be the array type,