< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java

Print this page
@@ -42,10 +42,11 @@
  import javax.lang.model.element.NestingKind;
  import javax.tools.JavaFileManager;
  import javax.tools.JavaFileObject;
  
  import com.sun.tools.javac.code.Source.Feature;
+ import com.sun.tools.javac.code.Type.ClassType.Flavor;
  import com.sun.tools.javac.comp.Annotate;
  import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
  import com.sun.tools.javac.code.*;
  import com.sun.tools.javac.code.Directive.*;
  import com.sun.tools.javac.code.Lint.LintCategory;

@@ -103,10 +104,18 @@
  
      /** Switch: allow modules.
       */
      boolean allowModules;
  
+     /** Switch: allow primitive classes.
+      */
+     boolean allowPrimitiveClasses;
+ 
+     /** Switch: allow value classes.
+      */
+     boolean allowValueClasses;
+ 
      /** Switch: allow sealed
       */
      boolean allowSealedTypes;
  
      /** Switch: allow records

@@ -275,10 +284,12 @@
          verbose         = options.isSet(Option.VERBOSE);
  
          Source source = Source.instance(context);
          preview = Preview.instance(context);
          allowModules     = Feature.MODULES.allowedInSource(source);
+         allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
+         allowValueClasses = Feature.VALUE_CLASSES.allowedInSource(source);
          allowRecords = Feature.RECORDS.allowedInSource(source);
          allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
  
          saveParameterNames = options.isSet(PARAMETERS);
  

@@ -470,13 +481,18 @@
              sigp++;
              return syms.intType;
          case 'J':
              sigp++;
              return syms.longType;
+         case 'Q':
          case 'L':
              {
                  // int oldsigp = sigp;
+                 if ((char) signature[sigp] == 'Q' && !allowPrimitiveClasses) {
+                     throw badClassFile("bad.class.signature",
+                             Convert.utf2string(signature, sigp, 10));
+                 }
                  Type t = classSigToType();
                  if (sigp < siglimit && signature[sigp] == '.')
                      throw badClassFile("deprecated inner class signature syntax " +
                                         "(please recompile from source)");
                  /*

@@ -531,15 +547,18 @@
      byte[] signatureBuffer = new byte[0];
      int sbp = 0;
      /** Convert class signature to type, where signature is implicit.
       */
      Type classSigToType() {
-         if (signature[sigp] != 'L')
+         byte prefix = signature[sigp];
+         if (prefix != 'L' && (!allowPrimitiveClasses || prefix != 'Q'))
              throw badClassFile("bad.class.signature",
                                 Convert.utf2string(signature, sigp, 10));
          sigp++;
          Type outer = Type.noType;
+         Name name;
+         ClassType.Flavor flavor;
          int startSbp = sbp;
  
          while (true) {
              final byte c = signature[sigp++];
              switch (c) {

@@ -547,24 +566,31 @@
              case ';': {         // end
                  ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
                                                           startSbp,
                                                           sbp - startSbp));
  
+                 // We are seeing QFoo; or LFoo; The name itself does not shine any light on default val-refness
+                 flavor = prefix == 'L' ? Flavor.L_TypeOf_X : Flavor.Q_TypeOf_X;
                  try {
-                     return (outer == Type.noType) ?
-                             t.erasure(types) :
-                         new ClassType(outer, List.nil(), t);
+                     if (outer == Type.noType) {
+                         ClassType et = (ClassType) t.erasure(types);
+                         // Todo: This spews out more objects than before, i.e no reuse with identical flavor
+                         return new ClassType(et.getEnclosingType(), List.nil(), et.tsym, et.getMetadata(), flavor);
+                     }
+                     return new ClassType(outer, List.nil(), t, TypeMetadata.EMPTY, flavor);
                  } finally {
                      sbp = startSbp;
                  }
              }
  
              case '<':           // generic arguments
                  ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
                                                           startSbp,
                                                           sbp - startSbp));
-                 outer = new ClassType(outer, sigToTypes('>'), t) {
+                 // We are seeing QFoo; or LFoo; The name itself does not shine any light on default val-refness
+                 flavor = prefix == 'L' ? Flavor.L_TypeOf_X : Flavor.Q_TypeOf_X;
+                 outer = new ClassType(outer, sigToTypes('>'), t, TypeMetadata.EMPTY, flavor) {
                          boolean completed = false;
                          @Override @DefinedBy(Api.LANGUAGE_MODEL)
                          public Type getEnclosingType() {
                              if (!completed) {
                                  completed = true;

@@ -623,11 +649,13 @@
                  //we have seen an enclosing non-generic class
                  if (outer != Type.noType) {
                      t = enterClass(names.fromUtf(signatureBuffer,
                                                   startSbp,
                                                   sbp - startSbp));
-                     outer = new ClassType(outer, List.nil(), t);
+                     // We are seeing QFoo; or LFoo; The name itself does not shine any light on default val-refness
+                     flavor = prefix == 'L' ? Flavor.L_TypeOf_X : Flavor.Q_TypeOf_X;
+                     outer = new ClassType(outer, List.nil(), t, TypeMetadata.EMPTY, flavor);
                  }
                  signatureBuffer[sbp++] = (byte)'$';
                  continue;
              case '/':
                  signatureBuffer[sbp++] = (byte)'.';

@@ -788,10 +816,19 @@
          AttributeReader[] readers = {
              // v45.3 attributes
  
              new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
                  protected void read(Symbol sym, int attrLen) {
+                     if (sym.isConstructor()  && sym.type.getParameterTypes().size() == 0) {
+                         int code_length = buf.getInt(bp + 4);
+                         if ((code_length == 1 && buf.getByte( bp + 8) == (byte) ByteCodes.return_) ||
+                                 (code_length == 5 && buf.getByte(bp + 8) == ByteCodes.aload_0 &&
+                                     buf.getByte( bp + 9) == (byte) ByteCodes.invokespecial &&
+                                             buf.getByte( bp + 12) == (byte) ByteCodes.return_)) {
+                                 sym.flags_field |= EMPTYNOARGCONSTR;
+                         }
+                     }
                      if (saveParameterNames)
                          ((MethodSymbol)sym).code = readCode(sym);
                      else
                          bp = bp + attrLen;
                  }

@@ -968,10 +1005,17 @@
                          List<Type> thrown = sym.type.getThrownTypes();
                          sym.type = poolReader.getType(nextChar());
                          //- System.err.println(" # " + sym.type);
                          if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
                              sym.type.asMethodType().thrown = thrown;
+                         // Map value class factory methods back to constructors for the benefit of earlier pipeline stages
+                         if (sym.kind == MTH  && sym.name == names.init && !sym.type.getReturnType().hasTag(TypeTag.VOID)) {
+                             sym.type = new MethodType(sym.type.getParameterTypes(),
+                                     syms.voidType,
+                                     sym.type.getThrownTypes(),
+                                     syms.methodClass);
+                         }
  
                      }
                  }
              },
  

@@ -2226,10 +2270,17 @@
                  throw badClassFile((flags & STATIC) == 0 ? "invalid.default.interface" : "invalid.static.interface",
                                     Integer.toString(majorVersion),
                                     Integer.toString(minorVersion));
              }
          }
+         if (name == names.init && ((flags & STATIC) != 0)) {
+             flags &= ~STATIC;
+             type = new MethodType(type.getParameterTypes(),
+                     syms.voidType,
+                     type.getThrownTypes(),
+                     syms.methodClass);
+         }
          validateMethodType(name, type);
          if (name == names.init && currentOwner.hasOuterInstance()) {
              // Sometimes anonymous classes don't have an outer
              // instance, however, there is no reliable way to tell so
              // we never strip this$n

@@ -2488,10 +2539,18 @@
              enterTypevars(c.owner, ct.getEnclosingType());
  
          // read flags, or skip if this is an inner class
          long f = nextChar();
          long flags = adjustClassFlags(f);
+         if (c == syms.objectType.tsym) {
+             flags &= ~IDENTITY_TYPE; // jlO lacks identity even while being a concrete class.
+         }
+         if ((flags & PRIMITIVE_CLASS) != 0) {
+             if ((flags & (FINAL | PRIMITIVE_CLASS | IDENTITY_TYPE)) != (FINAL | PRIMITIVE_CLASS)) {
+                 throw badClassFile("bad.access.flags", Flags.toString(flags));
+             }
+         }
          if ((flags & MODULE) == 0) {
              if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags;
              // read own class name and check that it matches
              currentModule = c.packge().modle;
              ClassSymbol self = poolReader.getClass(nextChar());

@@ -2734,15 +2793,34 @@
          }
          return flags;
      }
  
      long adjustClassFlags(long flags) {
+         if ((flags & (ABSTRACT | INTERFACE | ACC_VALUE | ACC_MODULE)) == 0) {
+             flags |= ACC_IDENTITY;
+         }
          if ((flags & ACC_MODULE) != 0) {
              flags &= ~ACC_MODULE;
              flags |= MODULE;
          }
-         return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
+         if ((flags & ACC_PRIMITIVE) != 0) {
+             flags &= ~ACC_PRIMITIVE;
+             if (allowPrimitiveClasses) {
+                 flags |= PRIMITIVE_CLASS;
+             }
+         }
+         if ((flags & ACC_VALUE) != 0) {
+             flags &= ~ACC_VALUE;
+             if (allowValueClasses) {
+                 flags |= VALUE_CLASS;
+             }
+         }
+         if ((flags & ACC_IDENTITY) != 0) {
+             flags &= ~ACC_IDENTITY;
+             flags |= IDENTITY_TYPE;
+         }
+         return flags;
      }
  
      /**
       * A subclass of JavaFileObject for the sourcefile attribute found in a classfile.
       * The attribute is only the last component of the original filename, so is unlikely
< prev index next >