< 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;

@@ -703,11 +704,11 @@
       * 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 ({@code "<init>"} and {@code "<clinit>"}).
+      * with special names ({@code "<init>"}, {@code "<vnew>"} and {@code "<clinit>"}).
       * 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

@@ -1621,10 +1622,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;

@@ -2738,10 +2740,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

@@ -2753,10 +2757,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 = "<init>";
              MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
              return getDirectConstructor(refc, ctor);
          }
  

@@ -3439,14 +3446,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.isConstructor());
+             assert(ctor.isObjectConstructor() || ctor.isStaticValueFactoryMethod());
              @SuppressWarnings("deprecation")
              Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
-             return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
+             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

@@ -3687,13 +3703,14 @@
              if (!isClassAccessible(refc)) {
                  return null;
              }
              Objects.requireNonNull(type);
              // implicit null-check of name
-             if (name.startsWith("<") && refKind != REF_newInvokeSpecial) {
+             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)) {

@@ -3709,14 +3726,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 (name.startsWith("<") && refKind != REF_newInvokeSpecial)
-                 throw new NoSuchMethodException("illegal method name: "+name);
+             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.

@@ -3816,19 +3846,19 @@
                  smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
              }
  
              // Step 3:
              Class<?> defc = m.getDeclaringClass();
-             if (!fullPrivilegeLookup && defc != refc) {
+             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.isConstructor())
+             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";

@@ -3899,16 +3929,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 ||
+                                (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) &&
-                            (defc == refc ||
+                            (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))

@@ -3981,11 +4011,10 @@
              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() &&
                  refc != lookupClass().getSuperclass() &&
                  refc.isAssignableFrom(lookupClass())) {

@@ -4125,11 +4154,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());
+             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

@@ -5031,11 +5060,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)
+             if (!PrimitiveClass.isPrimitiveValueType(type) && value == null)
                  return zero(Wrapper.OBJECT, type);
              return identity(type).bindTo(value);
          }
      }
  

@@ -5076,11 +5105,19 @@
       * @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);
+         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);
      }

@@ -5106,11 +5143,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);
+         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 >