< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Print this page
*** 24,10 ***
--- 24,11 ---
   */
  
  package java.lang.invoke;
  
  import jdk.internal.access.SharedSecrets;
+ import jdk.internal.value.PrimitiveClass;
  import jdk.internal.foreign.Utils;
  import jdk.internal.javac.PreviewFeature;
  import jdk.internal.misc.Unsafe;
  import jdk.internal.misc.VM;
  import jdk.internal.org.objectweb.asm.ClassReader;

*** 711,12 ***
       * the current class.  Again, this requirement is enforced by narrowing the
       * type of the leading parameter to the resulting method handle.
       * (See the Java Virtual Machine Specification, section {@jvms 4.10.1.9}.)
       * <p>
       * The JVM represents constructors and static initializer blocks as internal methods
!      * with special names ({@value ConstantDescs#INIT_NAME} and {@value
!      * ConstantDescs#CLASS_INIT_NAME}).
       * The internal syntax of invocation instructions allows them to refer to such internal
       * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
       * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
       * <p>
       * If the relationship between nested types is expressed directly through the
--- 712,12 ---
       * the current class.  Again, this requirement is enforced by narrowing the
       * type of the leading parameter to the resulting method handle.
       * (See the Java Virtual Machine Specification, section {@jvms 4.10.1.9}.)
       * <p>
       * The JVM represents constructors and static initializer blocks as internal methods
!      * with special names ({@value ConstantDescs#INIT_NAME},
!      * {@value ConstantDescs#VNEW_NAME} and {@value ConstantDescs#CLASS_INIT_NAME}).
       * The internal syntax of invocation instructions allows them to refer to such internal
       * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
       * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
       * <p>
       * If the relationship between nested types is expressed directly through the

*** 1636,10 ***
--- 1637,11 ---
          Lookup(Class<?> lookupClass) {
              this(lookupClass, null, FULL_POWER_MODES);
          }
  
          private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
+             assert PrimitiveClass.isPrimaryType(lookupClass);
              assert prevLookupClass == null || ((allowedModes & MODULE) == 0
                      && prevLookupClass.getModule() != lookupClass.getModule());
              assert !lookupClass.isArray() && !lookupClass.isPrimitive();
              this.lookupClass = lookupClass;
              this.prevLookupClass = prevLookupClass;

*** 2816,10 ***
--- 2818,12 ---
    ProcessBuilder.class, methodType(void.class, String[].class));
  ProcessBuilder pb = (ProcessBuilder)
    MH_newProcessBuilder.invoke("x", "y", "z");
  assertEquals("[x, y, z]", pb.command().toString());
           * }
+          *
+          *
           * @param refc the class or interface from which the method is accessed
           * @param type the type of the method, with the receiver argument omitted, and a void return type
           * @return the desired method handle
           * @throws NoSuchMethodException if the constructor does not exist
           * @throws IllegalAccessException if access checking fails

*** 2831,10 ***
--- 2835,13 ---
           */
          public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
              if (refc.isArray()) {
                  throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
              }
+             if (type.returnType() != void.class) {
+                 throw new NoSuchMethodException("Constructors must have void return type: " + refc.getName());
+             }
              String name = ConstantDescs.INIT_NAME;
              MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
              return getDirectConstructor(refc, ctor);
          }
  

*** 3526,14 ***
           *                                is set and {@code asVarargsCollector} fails
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
              MemberName ctor = new MemberName(c);
!             assert(ctor.isConstructor());
              @SuppressWarnings("deprecation")
              Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
!             return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
          }
  
          /**
           * Produces a method handle giving read access to a reflected field.
           * The type of the method handle will have a return type of the field's
--- 3533,23 ---
           *                                is set and {@code asVarargsCollector} fails
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
              MemberName ctor = new MemberName(c);
!             assert(ctor.isObjectConstructor() || ctor.isStaticValueFactoryMethod());
              @SuppressWarnings("deprecation")
              Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
!             Class<?> defc = c.getDeclaringClass();
+             if (ctor.isObjectConstructor()) {
+                 assert(ctor.getMethodType().returnType() == void.class);
+                 return lookup.getDirectConstructorNoSecurityManager(defc, ctor);
+             } else {
+                 // static init factory is a static method
+                 assert(ctor.isMethod() && ctor.getMethodType().returnType() == defc && ctor.getReferenceKind() == REF_invokeStatic) : ctor.toString();
+                 assert(!MethodHandleNatives.isCallerSensitive(ctor));  // must not be caller-sensitive
+                 return lookup.getDirectMethodNoSecurityManager(ctor.getReferenceKind(), defc, ctor, lookup);
+             }
          }
  
          /**
           * Produces a method handle giving read access to a reflected field.
           * The type of the method handle will have a return type of the field's

*** 3774,13 ***
              if (!isClassAccessible(refc)) {
                  return null;
              }
              Objects.requireNonNull(type);
              // implicit null-check of name
!             if (name.startsWith("<") && refKind != REF_newInvokeSpecial) {
                  return null;
              }
              return IMPL_NAMES.resolveOrNull(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes);
          }
  
          void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
              if (!isClassAccessible(refc)) {
--- 3790,14 ---
              if (!isClassAccessible(refc)) {
                  return null;
              }
              Objects.requireNonNull(type);
              // implicit null-check of name
!             if (isIllegalMethodName(refKind, name)) {
                  return null;
              }
+ 
              return IMPL_NAMES.resolveOrNull(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes);
          }
  
          void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
              if (!isClassAccessible(refc)) {

*** 3796,14 ***
                  type = type.getComponentType();
              }
              return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
          }
  
          /** Check name for an illegal leading "&lt;" character. */
          void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
!             if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
!                 throw new NoSuchMethodException("illegal method name: "+name);
          }
  
          /**
           * Find my trustable caller class if m is a caller sensitive method.
           * If this lookup object has original full privilege access, then the caller class is the lookupClass.
--- 3813,27 ---
                  type = type.getComponentType();
              }
              return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
          }
  
+         /*
+          * "<init>" can only be invoked via invokespecial
+          * "<vnew>" factory can only invoked via invokestatic
+          */
+         boolean isIllegalMethodName(byte refKind, String name) {
+             if (name.startsWith("<")) {
+                 return MemberName.VALUE_FACTORY_NAME.equals(name) ? refKind != REF_invokeStatic
+                                                                   : refKind != REF_newInvokeSpecial;
+             }
+             return false;
+         }
+ 
          /** Check name for an illegal leading "&lt;" character. */
          void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
!             if (isIllegalMethodName(refKind, name)) {
!                 throw new NoSuchMethodException("illegal method name: " + name + " " + refKind);
+             }
          }
  
          /**
           * Find my trustable caller class if m is a caller sensitive method.
           * If this lookup object has original full privilege access, then the caller class is the lookupClass.

*** 3903,19 ***
                  smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
              }
  
              // Step 3:
              Class<?> defc = m.getDeclaringClass();
!             if (!fullPrivilegeLookup && defc != refc) {
                  ReflectUtil.checkPackageAccess(defc);
              }
          }
  
          void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
              boolean wantStatic = (refKind == REF_invokeStatic);
              String message;
!             if (m.isConstructor())
                  message = "expected a method, not a constructor";
              else if (!m.isMethod())
                  message = "expected a method";
              else if (wantStatic != m.isStatic())
                  message = wantStatic ? "expected a static method" : "expected a non-static method";
--- 3933,19 ---
                  smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
              }
  
              // Step 3:
              Class<?> defc = m.getDeclaringClass();
!             if (!fullPrivilegeLookup && PrimitiveClass.asPrimaryType(defc) != PrimitiveClass.asPrimaryType(refc)) {
                  ReflectUtil.checkPackageAccess(defc);
              }
          }
  
          void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
              boolean wantStatic = (refKind == REF_invokeStatic);
              String message;
!             if (m.isObjectConstructor())
                  message = "expected a method, not a constructor";
              else if (!m.isMethod())
                  message = "expected a method";
              else if (wantStatic != m.isStatic())
                  message = wantStatic ? "expected a static method" : "expected a non-static method";

*** 3990,16 ***
          String accessFailedMessage(Class<?> refc, MemberName m) {
              Class<?> defc = m.getDeclaringClass();
              int mods = m.getModifiers();
              // check the class first:
              boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
!                                (defc == refc ||
                                  Modifier.isPublic(refc.getModifiers())));
              if (!classOK && (allowedModes & PACKAGE) != 0) {
                  // ignore previous lookup class to check if default package access
                  classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
!                            (defc == refc ||
                              VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
              }
              if (!classOK)
                  return "class is not public";
              if (Modifier.isPublic(mods))
--- 4020,16 ---
          String accessFailedMessage(Class<?> refc, MemberName m) {
              Class<?> defc = m.getDeclaringClass();
              int mods = m.getModifiers();
              // check the class first:
              boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
!                                (PrimitiveClass.asPrimaryType(defc) == PrimitiveClass.asPrimaryType(refc) ||
                                  Modifier.isPublic(refc.getModifiers())));
              if (!classOK && (allowedModes & PACKAGE) != 0) {
                  // ignore previous lookup class to check if default package access
                  classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
!                            (PrimitiveClass.asPrimaryType(defc) == PrimitiveClass.asPrimaryType(refc) ||
                              VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
              }
              if (!classOK)
                  return "class is not public";
              if (Modifier.isPublic(mods))

*** 4072,11 ***
              checkMethod(refKind, refc, method);
              // Optionally check with the security manager; this isn't needed for unreflect* calls.
              if (checkSecurity)
                  checkSecurityManager(refc, method);
              assert(!method.isMethodHandleInvoke());
- 
              if (refKind == REF_invokeSpecial &&
                  refc != lookupClass() &&
                  !refc.isInterface() && !lookupClass().isInterface() &&
                  refc != lookupClass().getSuperclass() &&
                  refc.isAssignableFrom(lookupClass())) {
--- 4102,10 ---

*** 4221,11 ***
              return getDirectConstructorCommon(refc, ctor, checkSecurity);
          }
          /** Common code for all constructors; do not call directly except from immediately above. */
          private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
                                                    boolean checkSecurity) throws IllegalAccessException {
!             assert(ctor.isConstructor());
              checkAccess(REF_newInvokeSpecial, refc, ctor);
              // Optionally check with the security manager; this isn't needed for unreflect* calls.
              if (checkSecurity)
                  checkSecurityManager(refc, ctor);
              assert(!MethodHandleNatives.isCallerSensitive(ctor));  // maybeBindCaller not relevant here
--- 4250,11 ---
              return getDirectConstructorCommon(refc, ctor, checkSecurity);
          }
          /** Common code for all constructors; do not call directly except from immediately above. */
          private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
                                                    boolean checkSecurity) throws IllegalAccessException {
!             assert(ctor.isObjectConstructor());
              checkAccess(REF_newInvokeSpecial, refc, ctor);
              // Optionally check with the security manager; this isn't needed for unreflect* calls.
              if (checkSecurity)
                  checkSecurityManager(refc, ctor);
              assert(!MethodHandleNatives.isCallerSensitive(ctor));  // maybeBindCaller not relevant here

*** 5127,11 ***
              value = w.convert(value, type);
              if (w.zero().equals(value))
                  return zero(w, type);
              return insertArguments(identity(type), 0, value);
          } else {
!             if (value == null)
                  return zero(Wrapper.OBJECT, type);
              return identity(type).bindTo(value);
          }
      }
  
--- 5156,11 ---
              value = w.convert(value, type);
              if (w.zero().equals(value))
                  return zero(w, type);
              return insertArguments(identity(type), 0, value);
          } else {
!             if (!PrimitiveClass.isPrimitiveValueType(type) && value == null)
                  return zero(Wrapper.OBJECT, type);
              return identity(type).bindTo(value);
          }
      }
  

*** 5172,11 ***
       * @see MethodHandles#explicitCastArguments
       * @since 9
       */
      public static MethodHandle zero(Class<?> type) {
          Objects.requireNonNull(type);
!         return type.isPrimitive() ?  zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
      }
  
      private static MethodHandle identityOrVoid(Class<?> type) {
          return type == void.class ? zero(type) : identity(type);
      }
--- 5201,19 ---
       * @see MethodHandles#explicitCastArguments
       * @since 9
       */
      public static MethodHandle zero(Class<?> type) {
          Objects.requireNonNull(type);
!         if (type.isPrimitive()) {
+             return zero(Wrapper.forPrimitiveType(type), type);
+         } else if (PrimitiveClass.isPrimitiveValueType(type)) {
+             // singleton default value
+             Object value = UNSAFE.uninitializedDefaultValue(type);
+             return identity(type).bindTo(value);
+         } else {
+             return zero(Wrapper.OBJECT, type);
+         }
      }
  
      private static MethodHandle identityOrVoid(Class<?> type) {
          return type == void.class ? zero(type) : identity(type);
      }

*** 5202,11 ***
          return dropArgumentsTrusted(zero(type.returnType()), 0, type.ptypes());
      }
  
      private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
      private static MethodHandle makeIdentity(Class<?> ptype) {
!         MethodType mtype = methodType(ptype, ptype);
          LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
          return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
      }
  
      private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
--- 5239,11 ---
          return dropArgumentsTrusted(zero(type.returnType()), 0, type.ptypes());
      }
  
      private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
      private static MethodHandle makeIdentity(Class<?> ptype) {
!         MethodType mtype = MethodType.methodType(ptype, ptype);
          LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
          return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
      }
  
      private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
< prev index next >