< prev index next >

src/java.base/share/classes/java/lang/Class.java

Print this page
@@ -70,16 +70,18 @@
  import java.util.stream.Collectors;
  
  import jdk.internal.loader.BootLoader;
  import jdk.internal.loader.BuiltinClassLoader;
  import jdk.internal.misc.Unsafe;
+ import jdk.internal.misc.ValhallaFeatures;
  import jdk.internal.module.Resources;
  import jdk.internal.reflect.CallerSensitive;
  import jdk.internal.reflect.CallerSensitiveAdapter;
  import jdk.internal.reflect.ConstantPool;
  import jdk.internal.reflect.Reflection;
  import jdk.internal.reflect.ReflectionFactory;
+ import jdk.internal.value.PrimitiveClass;
  import jdk.internal.vm.annotation.ForceInline;
  import jdk.internal.vm.annotation.IntrinsicCandidate;
  import sun.invoke.util.Wrapper;
  import sun.reflect.generics.factory.CoreReflectionFactory;
  import sun.reflect.generics.factory.GenericsFactory;

@@ -198,13 +200,13 @@
                                GenericDeclaration,
                                Type,
                                AnnotatedElement,
                                TypeDescriptor.OfField<Class<?>>,
                                Constable {
-     private static final int ANNOTATION= 0x00002000;
-     private static final int ENUM      = 0x00004000;
-     private static final int SYNTHETIC = 0x00001000;
+     private static final int ANNOTATION = 0x00002000;
+     private static final int ENUM       = 0x00004000;
+     private static final int SYNTHETIC  = 0x00001000;
  
      private static native void registerNatives();
      static {
          registerNatives();
      }

@@ -232,12 +234,26 @@
       * this method returns "class " followed by {@code getName}.
       *
       * @return a string representation of this {@code Class} object.
       */
      public String toString() {
-         String kind = isInterface() ? "interface " : isPrimitive() ? "" : "class ";
-         return kind.concat(getName());
+         String s = getName();
+         if (isPrimitive()) {
+             return s;
+         }
+         // Avoid invokedynamic based String concat, might be not available
+         // Prepend type of class
+         s = (isInterface() ? "interface " : "class ").concat(s);
+         if (isValue()) {
+             // prepend value class type
+             s = (isPrimitiveClass() ? "primitive " : "value ").concat(s);
+             if (isPrimitiveClass() && isPrimaryType()) {
+                 // Append .ref
+                 s = s.concat(".ref");
+             }
+         }
+         return s;
      }
  
      /**
       * Returns a string describing this {@code Class}, including
       * information about modifiers and type parameters.

@@ -286,18 +302,23 @@
                  } while (component.isArray());
                  sb.append(component.getName());
              } else {
                  // Class modifiers are a superset of interface modifiers
                  int modifiers = getModifiers() & Modifier.classModifiers();
+                 // Modifier.toString() below mis-interprets SYNCHRONIZED, STRICT, and VOLATILE bits
+                 modifiers &= ~(Modifier.SYNCHRONIZED | Modifier.STRICT | Modifier.VOLATILE);
                  if (modifiers != 0) {
                      sb.append(Modifier.toString(modifiers));
                      sb.append(' ');
                  }
  
                  if (isAnnotation()) {
                      sb.append('@');
                  }
+                 if (isValue()) {
+                     sb.append(isPrimitiveClass() ? "primitive " : "value ");
+                 }
                  if (isInterface()) { // Note: all annotation interfaces are interfaces
                      sb.append("interface");
                  } else {
                      if (isEnum())
                          sb.append("enum");

@@ -496,12 +517,12 @@
          return forName0(name, initialize, loader, caller);
      }
  
      /** Called after security check for system loader access checks have been made. */
      private static native Class<?> forName0(String name, boolean initialize,
-                                             ClassLoader loader,
-                                             Class<?> caller)
+                                     ClassLoader loader,
+                                     Class<?> caller)
          throws ClassNotFoundException;
  
  
      /**
       * Returns the {@code Class} with the given <a href="ClassLoader.html#binary-name">

@@ -586,10 +607,146 @@
          } else {
              return BootLoader.loadClass(module, name);
          }
      }
  
+     // set by VM if this class is an exotic type such as primitive class
+     // otherwise, these two fields are null
+     private transient Class<T> primaryType;
+     private transient Class<T> secondaryType;
+ 
+     /**
+      * Returns {@code true} if this class is a primitive class.
+      * <p>
+      * Each primitive class has a {@linkplain #isPrimaryType() primary type}
+      * representing the <em>primitive reference type</em> and a
+      * {@linkplain #isPrimitiveValueType() secondary type} representing
+      * the <em>primitive value type</em>.  The primitive reference type
+      * and primitive value type can be obtained by calling the
+      * {@link #asPrimaryType()} and {@link #asValueType} method
+      * of a primitive class respectively.
+      * <p>
+      * A primitive class is a {@linkplain #isValue() value class}.
+      *
+      * @return {@code true} if this class is a primitive class, otherwise {@code false}
+      * @see #isValue()
+      * @see #asPrimaryType()
+      * @see #asValueType()
+      * @since Valhalla
+      */
+     /* package */ boolean isPrimitiveClass() {
+         return (this.getModifiers() & PrimitiveClass.PRIMITIVE_CLASS) != 0;
+     }
+ 
+     /**
+      * {@return {@code true} if this {@code Class} object represents an identity
+      * class or interface; otherwise {@code false}}
+      *
+      * If this {@code Class} object represents an array type, then this method
+      * returns {@code true}.
+      * If this {@code Class} object represents a primitive type, or {@code void},
+      * then this method returns {@code false}.
+      *
+      * @since Valhalla
+      */
+     public native boolean isIdentity();
+ 
+     /**
+      * {@return {@code true} if this {@code Class} object represents a value
+      * class or interface; otherwise {@code false}}
+      *
+      * If this {@code Class} object represents an array type, a primitive type, or
+      * {@code void}, then this method returns {@code false}.
+      *
+      * @since Valhalla
+      */
+     public boolean isValue() {
+         return (this.getModifiers() & Modifier.VALUE) != 0;
+     }
+ 
+     /**
+      * Returns a {@code Class} object representing the primary type
+      * of this class or interface.
+      * <p>
+      * If this {@code Class} object represents a primitive type or an array type,
+      * then this method returns this class.
+      * <p>
+      * If this {@code Class} object represents a {@linkplain #isPrimitiveClass()
+      * primitive class}, then this method returns the <em>primitive reference type</em>
+      * type of this primitive class.
+      * <p>
+      * Otherwise, this {@code Class} object represents a non-primitive class or interface
+      * and this method returns this class.
+      *
+      * @return the {@code Class} representing the primary type of
+      *         this class or interface
+      * @since Valhalla
+      */
+     @IntrinsicCandidate
+     /* package */ Class<?> asPrimaryType() {
+         return isPrimitiveClass() ? primaryType : this;
+     }
+ 
+     /**
+      * Returns a {@code Class} object representing the <em>primitive value type</em>
+      * of this class if this class is a {@linkplain #isPrimitiveClass() primitive class}.
+      *
+      * @apiNote Alternatively, this method returns null if this class is not
+      *          a primitive class rather than throwing UOE.
+      *
+      * @return the {@code Class} representing the {@linkplain #isPrimitiveValueType()
+      * primitive value type} of this class if this class is a primitive class
+      * @throws UnsupportedOperationException if this class or interface
+      *         is not a primitive class
+      * @since Valhalla
+      */
+     @IntrinsicCandidate
+     /* package */ Class<?> asValueType() {
+         if (isPrimitiveClass())
+             return secondaryType;
+ 
+         throw new UnsupportedOperationException(this.getName().concat(" is not a primitive class"));
+     }
+ 
+     /**
+      * Returns {@code true} if this {@code Class} object represents the primary type
+      * of this class or interface.
+      * <p>
+      * If this {@code Class} object represents a primitive type or an array type,
+      * then this method returns {@code true}.
+      * <p>
+      * If this {@code Class} object represents a {@linkplain #isPrimitiveClass()
+      * primitive}, then this method returns {@code true} if this {@code Class}
+      * object represents a primitive reference type, or returns {@code false}
+      * if this {@code Class} object represents a primitive value type.
+      * <p>
+      * If this {@code Class} object represents a non-primitive class or interface,
+      * then this method returns {@code true}.
+      *
+      * @return {@code true} if this {@code Class} object represents
+      * the primary type of this class or interface
+      * @since Valhalla
+      */
+     /* package */ boolean isPrimaryType() {
+         if (isPrimitiveClass()) {
+             return this == primaryType;
+         }
+         return true;
+     }
+ 
+     /**
+      * Returns {@code true} if this {@code Class} object represents
+      * a {@linkplain #isPrimitiveClass() primitive} value type.
+      *
+      * @return {@code true} if this {@code Class} object represents
+      * the value type of a primitive class
+      * @since Valhalla
+      */
+     /* package */ boolean isPrimitiveValueType() {
+         return isPrimitiveClass() && this == secondaryType;
+     }
+ 
      /**
       * Creates a new instance of the class represented by this {@code Class}
       * object.  The class is instantiated as if by a {@code new}
       * expression with an empty argument list.  The class is initialized if it
       * has not already been initialized.

@@ -1293,10 +1450,12 @@
       * in an integer. The modifiers consist of the Java Virtual Machine's
       * constants for {@code public}, {@code protected},
       * {@code private}, {@code final}, {@code static},
       * {@code abstract} and {@code interface}; they should be decoded
       * using the methods of class {@code Modifier}.
+      * The modifiers also include the Java Virtual Machine's constants for
+      * {@code identity class} and {@code value class}.
       *
       * <p> If the underlying class is an array class, then its
       * {@code public}, {@code private} and {@code protected}
       * modifiers are the same as those of its component type.  If this
       * {@code Class} object represents a primitive type or void, its

@@ -1322,11 +1481,11 @@
       * @jls 9.1.1. Interface Modifiers
       */
      @IntrinsicCandidate
      public native int getModifiers();
  
-     /**
+    /**
       * {@return an unmodifiable set of the {@linkplain AccessFlag access
       * flags} for this class, possibly empty}
       *
       * <p> If the underlying class is an array class, then its
       * {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}

@@ -1353,32 +1512,30 @@
          var location = (isMemberClass() || isLocalClass() ||
                          isAnonymousClass() || isArray()) ?
              AccessFlag.Location.INNER_CLASS :
              AccessFlag.Location.CLASS;
          return AccessFlag.maskToAccessFlags((location == AccessFlag.Location.CLASS) ?
-                                             getClassAccessFlagsRaw() :
-                                             getModifiers(),
+                                             getClassAccessFlagsRaw() & (~0x800) :
+                                             getModifiers() & (~0x800), // suppress unspecified bit
                                              location);
      }
  
-     /**
+    /**
       * Gets the signers of this class.
       *
       * @return  the signers of this class, or null if there are no signers.  In
       *          particular, this method returns null if this {@code Class} object represents
       *          a primitive type or void.
       * @since   1.1
       */
      public native Object[] getSigners();
  
- 
      /**
       * Set the signers of this class.
       */
      native void setSigners(Object[] signers);
  
- 
      /**
       * If this {@code Class} object represents a local or anonymous
       * class within a method, returns a {@link
       * java.lang.reflect.Method Method} object representing the
       * immediately enclosing method of the underlying class. Returns

@@ -1515,13 +1672,17 @@
  
          boolean isPartial() {
              return enclosingClass == null || name == null || descriptor == null;
          }
  
-         boolean isConstructor() { return !isPartial() && "<init>".equals(name); }
+         boolean isObjectConstructor() { return !isPartial() && "<init>".equals(name); }
  
-         boolean isMethod() { return !isPartial() && !isConstructor() && !"<clinit>".equals(name); }
+         boolean isValueFactoryMethod() { return !isPartial() && "<vnew>".equals(name); }
+ 
+         boolean isMethod() { return !isPartial() && !isObjectConstructor()
+                                         && !isValueFactoryMethod()
+                                         && !"<clinit>".equals(name); }
  
          Class<?> getEnclosingClass() { return enclosingClass; }
  
          String getName() { return name; }
  

@@ -1576,11 +1737,11 @@
          EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
  
          if (enclosingInfo == null)
              return null;
          else {
-             if (!enclosingInfo.isConstructor())
+             if (!enclosingInfo.isObjectConstructor() && !enclosingInfo.isValueFactoryMethod())
                  return null;
  
              ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
                                                                          getFactory());
              Type []    parameterTypes   = typeInfo.getParameterTypes();

@@ -1756,14 +1917,19 @@
                  int dimensions = 0;
                  do {
                      dimensions++;
                      cl = cl.getComponentType();
                  } while (cl.isArray());
-                 return cl.getName().concat("[]".repeat(dimensions));
+                 return cl.getTypeName().concat("[]".repeat(dimensions));
              } catch (Throwable e) { /*FALLTHRU*/ }
          }
-         return getName();
+         if (isPrimitiveClass()) {
+             // TODO: null-default
+             return isPrimaryType() ? getName().concat(".ref") : getName();
+         } else {
+             return getName();
+         }
      }
  
      /**
       * Returns the canonical name of the underlying class as
       * defined by <cite>The Java Language Specification</cite>.

@@ -3673,11 +3839,11 @@
              if (arrayContentsEq(parameterTypes,
                                  fact.getExecutableSharedParameterTypes(constructor))) {
                  return constructor;
              }
          }
-         throw new NoSuchMethodException(methodToString("<init>", parameterTypes));
+         throw new NoSuchMethodException(methodToString(isValue() ? "<vnew>" : "<init>", parameterTypes));
      }
  
      //
      // Other helpers and base implementation
      //

@@ -3977,10 +4143,13 @@
       * @since 1.5
       */
      @SuppressWarnings("unchecked")
      @IntrinsicCandidate
      public T cast(Object obj) {
+         if (isPrimitiveValueType() && obj == null)
+             throw new NullPointerException(getName() + " is a primitive value type");
+ 
          if (obj != null && !isInstance(obj))
              throw new ClassCastException(cannotCastMsg(obj));
          return (T) obj;
      }
  

@@ -4272,11 +4441,11 @@
       *
       * @return an array representing the superinterfaces
       * @since 1.8
       */
      public AnnotatedType[] getAnnotatedInterfaces() {
-          return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
+         return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
      }
  
      private native Class<?> getNestHost0();
  
      /**

@@ -4487,24 +4656,26 @@
          if (isPrimitive())
              return Wrapper.forPrimitiveType(this).basicTypeString();
  
          if (isArray()) {
              return "[" + componentType.descriptorString();
-         } else if (isHidden()) {
+         }
+         char typeDesc = isPrimitiveValueType() ? 'Q' : 'L';
+         if (isHidden()) {
              String name = getName();
              int index = name.indexOf('/');
              return new StringBuilder(name.length() + 2)
-                     .append('L')
+                     .append(typeDesc)
                      .append(name.substring(0, index).replace('.', '/'))
                      .append('.')
                      .append(name, index + 1, name.length())
                      .append(';')
                      .toString();
          } else {
              String name = getName().replace('.', '/');
              return new StringBuilder(name.length() + 2)
-                     .append('L')
+                     .append(typeDesc)
                      .append(name)
                      .append(';')
                      .toString();
          }
      }
< prev index next >