changeset 448:5e0f932f8ef0

meth-info-8008688.patch: incorporate review comments
author jrose
date Tue, 02 Jul 2013 18:23:10 -0700
parents a49289c99587
children f7504de08f94
files meth-info-8008688.patch
diffstat 1 files changed, 103 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/meth-info-8008688.patch	Tue Jul 02 17:15:57 2013 -0700
+++ b/meth-info-8008688.patch	Tue Jul 02 18:23:10 2013 -0700
@@ -24,7 +24,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/src/share/classes/java/lang/invoke/InfoFromMemberName.java
-@@ -0,0 +1,139 @@
+@@ -0,0 +1,145 @@
 +/*
 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -107,7 +107,11 @@
 +    @Override
 +    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
 +        if (member.isMethodHandleInvoke() && !member.isVarargs()) {
-+            // this member is an instance of a signature-polymorphic method, which cannot be reflected
++            // This member is an instance of a signature-polymorphic method, which cannot be reflected
++            // A method handle invoker can come in either of two forms:
++            // A generic placeholder (present in the source code, and varargs)
++            // and a signature-polymorphic instance (synthetic and not varargs).
++            // For more information see comments on {@link MethodHandleNatives#linkMethod}.
 +            throw new IllegalArgumentException("cannot reflect signature polymorphic method");
 +        }
 +        Member mem = AccessController.doPrivileged(new PrivilegedAction<Member>() {
@@ -120,7 +124,9 @@
 +                }
 +            });
 +        try {
-+            checkAccess(mem, lookup);
++            Class<?> defc = getDeclaringClass();
++            byte refKind = (byte) getReferenceKind();
++            lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
 +        } catch (IllegalAccessException ex) {
 +            throw new IllegalArgumentException(ex);
 +        }
@@ -151,17 +157,17 @@
 +        }
 +    }
 +
-+    private void checkAccess(Member mem, Lookup lookup) throws IllegalAccessException {
-+        byte refKind = (byte) getReferenceKind();
++    private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
 +        if (mem instanceof Method) {
 +            boolean wantSpecial = (refKind == REF_invokeSpecial);
-+            lookup.checkAccess(refKind, getDeclaringClass(), new MemberName((Method) mem, wantSpecial));
++            return new MemberName((Method) mem, wantSpecial);
 +        } else if (mem instanceof Constructor) {
-+            lookup.checkAccess(refKind, getDeclaringClass(), new MemberName((Constructor) mem));
++            return new MemberName((Constructor) mem);
 +        } else if (mem instanceof Field) {
 +            boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
-+            lookup.checkAccess(refKind, getDeclaringClass(), new MemberName((Field) mem, isSetter));
++            return new MemberName((Field) mem, isSetter);
 +        }
++        throw new InternalError(mem.getClass().getName());
 +    }
 +}
 diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
@@ -207,13 +213,16 @@
  
      /** Utility method to query the modifier flags of this member. */
      public boolean isStatic() {
-@@ -482,12 +486,24 @@
+@@ -482,12 +486,27 @@
          m.getClass();  // NPE check
          // fill in vmtarget, vmindex while we have m in hand:
          MethodHandleNatives.init(this, m);
 +        if (clazz == null) {  // MHN.init failed
 +            if (m.getDeclaringClass() == MethodHandle.class &&
 +                isMethodHandleInvokeName(m.getName())) {
++                // The JVM did not reify this signature-polymorphic instance.
++                // Need a special case here.
++                // See comments on MethodHandleNatives.linkMethod.
 +                MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
 +                int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
 +                init(MethodHandle.class, m.getName(), type, flags);
@@ -233,11 +242,16 @@
              if (getReferenceKind() == REF_invokeVirtual)
                  changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
              else if (getReferenceKind() == REF_invokeInterface)
-@@ -562,6 +578,17 @@
+@@ -562,6 +581,22 @@
          initResolved(true);
      }
  
-+    /** Create a name for a signature-polymorphic invoker. */
++    /**
++     * Create a name for a signature-polymorphic invoker.
++     * This is a placeholder for a signature-polymorphic instance
++     * (of MH.invokeExact, etc.) that the JVM does not reify.
++     * See comments on {@link MethodHandleNatives#linkMethod}.
++     */
 +    static MemberName makeMethodHandleInvoke(String name, MethodType type) {
 +        return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
 +    }
@@ -439,12 +453,11 @@
 diff --git a/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
 --- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
-@@ -24,80 +24,247 @@
+@@ -24,80 +24,246 @@
   */
  
  package java.lang.invoke;
 +
-+import java.security.*;
 +import java.lang.reflect.*;
 +import java.util.*;
  import java.lang.invoke.MethodHandleNatives.Constants;
@@ -760,20 +773,86 @@
      static boolean refKindHasReceiver(byte refKind) {
          assert(refKindIsValid(refKind));
          return (refKind & 1) != 0;
+@@ -313,7 +316,65 @@
+      * The method assumes the following arguments on the stack:
+      * 0: the method handle being invoked
+      * 1-N: the arguments to the method handle invocation
+-     * N+1: an implicitly added type argument (the given MethodType)
++     * N+1: an optional, implicitly added argument (typically the given MethodType)
++     * <p>
++     * The nominal method at such a call site is an instance of
++     * a signature-polymorphic method (see @PolymorphicSignature).
++     * Such method instances are user-visible entities which are
++     * "split" from the generic placeholder method in {@code MethodHandle}.
++     * (Note that the placeholder method is not identical with any of
++     * its instances.  If invoked reflectively, is guaranteed to throw an
++     * {@code UnsupportedOperationException}.)
++     * If the signature-polymorphic method instance is ever reified,
++     * it appears as a "copy" of the original placeholder
++     * (a native final member of {@code MethodHandle}) except
++     * that its type descriptor has shape required by the instance,
++     * and the method instance is <em>not</em> varargs.
++     * The method instance is also marked synthetic, since the
++     * method (by definition) does not appear in Java source code.
++     * <p>
++     * The JVM is allowed to reify this method as instance metadata.
++     * For example, {@code invokeBasic} is always reified.
++     * But the JVM may instead call {@code linkMethod}.
++     * If the result is an * ordered pair of a {@code (method, appendix)},
++     * the method gets all the arguments (0..N inclusive)
++     * plus the appendix (N+1), and uses the appendix to complete the call.
++     * In this way, one reusable method (called a "linker method")
++     * can perform the function of any number of polymorphic instance
++     * methods.
++     * <p>
++     * Linker methods are allowed to be weakly typed, with any or
++     * all references rewritten to {@code Object} and any primitives
++     * (except {@code long}/{@code float}/{@code double})
++     * rewritten to {@code int}.
++     * A linker method is trusted to return a strongly typed result,
++     * according to the specific method type descriptor of the
++     * signature-polymorphic instance it is emulating.
++     * This can involve (as necessary) a dynamic check using
++     * data extracted from the appendix argument.
++     * <p>
++     * The JVM does not inspect the appendix, other than to pass
++     * it verbatim to the linker method at every call.
++     * This means that the JDK runtime has wide latitude
++     * for choosing the shape of each linker method and its
++     * corresponding appendix.
++     * Linker methods should be generated from {@code LambdaForm}s
++     * so that they do not become visible on stack traces.
++     * <p>
++     * The {@code linkMethod} call is free to omit the appendix
++     * (returning null) and instead emulate the required function
++     * completely in the linker method.
++     * As a corner case, if N==255, no appendix is possible.
++     * In this case, the method returned must be custom-generated to
++     * to perform any needed type checking.
++     * <p>
++     * If the JVM does not reify a method at a call site, but instead
++     * calls {@code linkMethod}, the corresponding call represented
++     * in the bytecodes may mention a valid method which is not
++     * representable with a {@code MemberName}.
++     * Therefore, use cases for {@code linkMethod} tend to correspond to
++     * special cases in reflective code such as {@code findVirtual}
++     * or {@code revealDirect}.
+      */
+     static MemberName linkMethod(Class<?> callerClass, int refKind,
+                                  Class<?> defc, String name, Object type,
 diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
 --- a/src/share/classes/java/lang/invoke/MethodHandles.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -26,8 +26,7 @@
+@@ -26,8 +26,6 @@
  package java.lang.invoke;
  
  import java.lang.reflect.*;
 -import java.security.AccessController;
 -import java.security.PrivilegedAction;
-+import java.security.*;
  import java.util.List;
  import java.util.ArrayList;
  import java.util.Arrays;
-@@ -53,6 +52,7 @@
+@@ -53,6 +51,7 @@
   * </ul>
   * <p>
   * @author John Rose, JSR 292 EG
@@ -781,7 +860,7 @@
   */
  public class MethodHandles {
  
-@@ -96,6 +96,38 @@
+@@ -96,6 +95,38 @@
      }
  
      /**
@@ -820,7 +899,7 @@
       * A <em>lookup object</em> is a factory for creating method handles,
       * when the creation requires access checking.
       * Method handles do not perform
-@@ -651,6 +683,7 @@
+@@ -651,6 +682,7 @@
                  return invoker(type);
              if ("invokeExact".equals(name))
                  return exactInvoker(type);
@@ -828,7 +907,7 @@
              return null;
          }
  
-@@ -896,6 +929,10 @@
+@@ -896,6 +928,10 @@
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflect(Method m) throws IllegalAccessException {
@@ -839,7 +918,7 @@
              MemberName method = new MemberName(m);
              byte refKind = method.getReferenceKind();
              if (refKind == REF_invokeSpecial)
-@@ -904,6 +941,12 @@
+@@ -904,6 +940,12 @@
              Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
              return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
          }
@@ -852,7 +931,7 @@
  
          /**
           * Produces a method handle for a reflected method.
-@@ -1008,6 +1051,47 @@
+@@ -1008,6 +1050,46 @@
              return unreflectField(f, true);
          }
  
@@ -887,9 +966,8 @@
 +                refKind = REF_invokeInterface;
 +            // Check SM permissions and member access before cracking.
 +            try {
-+                //@@checkSecurityManager(defc, member, lookupClass());
 +                checkSecurityManager(defc, member);
-+                checkAccess(member.getReferenceKind(), defc, member);
++                checkAccess(refKind, defc, member);
 +            } catch (IllegalAccessException ex) {
 +                throw new IllegalArgumentException(ex);
 +            }
@@ -900,7 +978,7 @@
          /// Helper methods, all package-private.
  
          MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-@@ -1244,12 +1328,12 @@
+@@ -1244,12 +1326,12 @@
          private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
                                                     boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
              checkMethod(refKind, refc, method);
@@ -915,7 +993,7 @@
                  refc != (refcAsSuper = lookupClass().getSuperclass()) &&
                  refc.isAssignableFrom(lookupClass())) {
                  assert(!method.getName().equals("<init>"));  // not this code path
-@@ -1277,9 +1361,6 @@
+@@ -1277,9 +1359,6 @@
                  mh = restrictReceiver(method, mh, lookupClass());
              return mh;
          }