< prev index next >

make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java

Print this page
*** 181,10 ***
--- 181,22 ---
   * Note: the versions are expected to be a single character.
   *
   */
  public class CreateSymbols {
  
+     /**
+      * <p>Support for a "preview version" of classfiles when running with preview
+      * mode. This is modeled as a new version (@) and since preview mode is only
+      * supported for the current version, a single identifier token is sufficient.
+      *
+      * <p>For example, inside ct.sym, 27 will be modeled as 'R', and the preview
+      * for 27 will be '@'. Classfiles unchanged between 27 and 27-preview will
+      * not be duplicated (in the same way classfiles that are common between 26
+      * and 27 are shared).
+      */
+     private static final String PREVIEW_VERSION = "@";
+ 
      //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
      /**Create sig files for ct.sym reading the classes description from the directory that contains
       * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
       */
      public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation,

*** 210,24 ***
--- 222,32 ---
                                             .collect(Collectors.toSet());
  
          loadVersionClassesFromDirectory(data.classes, data.modules, moduleClassPath,
                                          includedModules, currentVersion, previousVersion);
  
+         loadVersionClassesFromDirectory(data.classes, data.modules, moduleClassPath,
+                 includedModules, PREVIEW_VERSION, currentVersion);
+ 
          stripNonExistentAnnotations(data);
          splitHeaders(data.classes);
  
          Map<String, Map<Character, String>> package2Version2Module = new HashMap<>();
          Map<String, Set<FileData>> directory2FileData = new TreeMap<>();
  
+         String currentVersionFin = currentVersion;
+ 
          for (ModuleDescription md : data.modules.values()) {
              for (ModuleHeaderDescription mhd : md.header) {
                  writeModulesForVersions(directory2FileData,
                                          md,
                                          mhd,
                                          mhd.versions,
                                          version -> {
                                              String versionString = Character.toString(version);
+                                             if (PREVIEW_VERSION.equals(versionString)) {
+                                                 versionString = currentVersionFin;
+                                             }
                                              int versionNumber = Integer.parseInt(versionString, Character.MAX_RADIX);
                                              versionString = Integer.toString(versionNumber);
                                              if (versionNumber == currentVersionParsed && !preReleaseTag.isEmpty()) {
                                                  versionString = versionString + "-" + preReleaseTag;
                                              }

*** 304,20 ***
--- 324,25 ---
              "Ljdk/internal/javac/Restricted+Annotation;";
      private static final String VALUE_BASED_ANNOTATION =
              "Ljdk/internal/ValueBased;";
      private static final String VALUE_BASED_ANNOTATION_INTERNAL =
              "Ljdk/internal/ValueBased+Annotation;";
+     private static final String MIGRATED_VALUE_CLASS_ANNOTATION =
+             "Ljdk/internal/MigratedValueClass;";
+     private static final String MIGRATED_VALUE_CLASS_ANNOTATION_INTERNAL =
+             "Ljdk/internal/MigratedValueClass+Annotation;";
      private static final String REQUIRES_IDENTITY_ANNOTATION =
              "Ljdk/internal/RequiresIdentity;";
      private static final String REQUIRES_IDENTITY_ANNOTATION_INTERNAL =
              "Ljdk/internal/RequiresIdentity+Annotation;";
      public static final Set<String> HARDCODED_ANNOTATIONS = new HashSet<>(
              List.of("Ljdk/Profile+Annotation;",
                      "Lsun/Proprietary+Annotation;",
                      PREVIEW_FEATURE_ANNOTATION_OLD,
                      PREVIEW_FEATURE_ANNOTATION_NEW,
                      VALUE_BASED_ANNOTATION,
+                     MIGRATED_VALUE_CLASS_ANNOTATION,
                      RESTRICTED_ANNOTATION,
                      REQUIRES_IDENTITY_ANNOTATION));
  
      private void stripNonExistentAnnotations(LoadDescriptions data) {
          Set<String> allClasses = data.classes.name2Class.keySet();

*** 807,10 ***
--- 832,13 ---
                      ClassDescription classDescription,
                      ClassHeaderDescription header,
                      String module,
                      String version) throws IOException {
          var classFile = ClassFile.of().build(ClassDesc.ofInternalName(classDescription.name), clb -> {
+             if (header.preview) {
+                 clb.withVersion(ClassFile.latestMajorVersion(), ClassFile.PREVIEW_MINOR_VERSION);
+             }
              if (header.extendsAttr != null)
                  clb.withSuperclass(ClassDesc.ofInternalName(header.extendsAttr));
              clb.withInterfaceSymbols(header.implementsAttr.stream().map(ClassDesc::ofInternalName).collect(Collectors.toList()))
                      .withFlags(header.flags);
              for (FieldDescription fieldDesc : classDescription.fields) {

*** 1032,10 ***
--- 1060,16 ---
              //the non-public ValueBased annotation will not be available in ct.sym,
              //replace with purely synthetic javac-internal annotation:
              annotationType = VALUE_BASED_ANNOTATION_INTERNAL;
          }
  
+         if (MIGRATED_VALUE_CLASS_ANNOTATION.equals(annotationType)) {
+             //the non-public MigratedValueClass annotation will not be available in ct.sym,
+             //replace with purely synthetic javac-internal annotation:
+             annotationType = MIGRATED_VALUE_CLASS_ANNOTATION_INTERNAL;
+         }
+ 
          if (REQUIRES_IDENTITY_ANNOTATION.equals(annotationType)) {
              //the non-public RequiresIdentity annotation will not be available in ct.sym,
              //replace with purely synthetic javac-internal annotation:
              annotationType = REQUIRES_IDENTITY_ANNOTATION_INTERNAL;
          }

*** 1303,20 ***
          ExcludeIncludeList currentEIList = new ExcludeIncludeList(includes,
                  privateIncludes,
                  Collections.emptySet());
  
          try {
              Map<Path, ModuleHeaderDescription> modulePath2Header = new HashMap<>();
!             List<Path> pendingExportedDirectories = new ArrayList<>();
  
              try (DirectoryStream<Path> ds = Files.newDirectoryStream(modulesDirectory)) {
                  for (Path p : ds) {
                      if (!includedModules.contains(p.getFileName().toString())) {
                          continue;
                      }
  
!                     Path moduleInfo = p.resolve("module-info.class");
  
                      if (Files.isReadable(moduleInfo)) {
                          ModuleDescription md = inspectModuleInfoClassFile(Files.readAllBytes(moduleInfo),
                                      currentVersionModules, version);
                          if (md == null) {
--- 1337,21 ---
          ExcludeIncludeList currentEIList = new ExcludeIncludeList(includes,
                  privateIncludes,
                  Collections.emptySet());
  
          try {
+             record ExportedDir(Path modulePath, Path exportedDir) {}
              Map<Path, ModuleHeaderDescription> modulePath2Header = new HashMap<>();
!             List<ExportedDir> pendingExportedDirectories = new ArrayList<>();
  
              try (DirectoryStream<Path> ds = Files.newDirectoryStream(modulesDirectory)) {
                  for (Path p : ds) {
                      if (!includedModules.contains(p.getFileName().toString())) {
                          continue;
                      }
  
!                     Path moduleInfo = resolvePossiblyPreviewClassFile(version, p, p.resolve("module-info.class"));
  
                      if (Files.isReadable(moduleInfo)) {
                          ModuleDescription md = inspectModuleInfoClassFile(Files.readAllBytes(moduleInfo),
                                      currentVersionModules, version);
                          if (md == null) {

*** 1331,11 ***
                                                          .map(e -> e.packageName + '/')
                                                          .collect(Collectors.toSet());
  
                          for (String dir : currentModuleExports) {
                              includes.add(dir);
!                             pendingExportedDirectories.add(p.resolve(dir));
                          }
                      } else {
                          throw new IllegalArgumentException("Included module: " +
                                                             p.getFileName() +
                                                             " does not have a module-info.class");
--- 1366,11 ---
                                                          .map(e -> e.packageName + '/')
                                                          .collect(Collectors.toSet());
  
                          for (String dir : currentModuleExports) {
                              includes.add(dir);
!                             pendingExportedDirectories.add(new ExportedDir(p, p.resolve(dir)));
                          }
                      } else {
                          throw new IllegalArgumentException("Included module: " +
                                                             p.getFileName() +
                                                             " does not have a module-info.class");

*** 1343,17 ***
                  }
              }
  
              List<String> pendingExtraClasses = new ArrayList<>();
  
!             for (Path exported : pendingExportedDirectories) {
!                 try (DirectoryStream<Path> ds = Files.newDirectoryStream(exported)) {
                      for (Path p2 : ds) {
                          if (!Files.isRegularFile(p2) || !p2.getFileName().toString().endsWith(".class")) {
                              continue;
                          }
  
                          loadFromDirectoryHandleClassFile(p2, currentVersionClasses,
                                                           currentEIList, version,
                                                           pendingExtraClasses);
                      }
                  }
--- 1378,19 ---
                  }
              }
  
              List<String> pendingExtraClasses = new ArrayList<>();
  
!             for (ExportedDir exported : pendingExportedDirectories) {
!                 try (DirectoryStream<Path> ds = Files.newDirectoryStream(exported.exportedDir())) {
                      for (Path p2 : ds) {
                          if (!Files.isRegularFile(p2) || !p2.getFileName().toString().endsWith(".class")) {
                              continue;
                          }
  
+                         p2 = resolvePossiblyPreviewClassFile(version, exported.modulePath(), p2);
+ 
                          loadFromDirectoryHandleClassFile(p2, currentVersionClasses,
                                                           currentEIList, version,
                                                           pendingExtraClasses);
                      }
                  }

*** 1368,10 ***
--- 1405,11 ---
  
                  for (Entry<Path, ModuleHeaderDescription> e : modulePath2Header.entrySet()) {
                      Path currentPath = e.getKey().resolve(current + ".class");
  
                      if (Files.isReadable(currentPath)) {
+                         currentPath = resolvePossiblyPreviewClassFile(version, e.getKey(), currentPath);
                          String pack = current.substring(0, current.lastIndexOf('/'));
  
                          e.getValue().extraModulePackages.add(pack);
  
                          loadFromDirectoryHandleClassFile(currentPath, currentVersionClasses,

*** 1400,10 ***
--- 1438,25 ---
                                   todo.addAll(superTypes);
                               });
          }
      }
  
+     private Path resolvePossiblyPreviewClassFile(String version, Path moduleClassDir, Path classfile) {
+         if (!PREVIEW_VERSION.equals(version)) {
+             return classfile;
+         }
+ 
+         Path relativePath = moduleClassDir.relativize(classfile);
+         Path previewCandidate = moduleClassDir.resolve("META-INF").resolve("preview").resolve(relativePath);
+ 
+         if (Files.exists(previewCandidate)) {
+             return previewCandidate;
+         }
+ 
+         return classfile;
+     }
+ 
      private void finishClassLoading(ClassList classes, Map<String, ModuleDescription> modules, Map<String, ModuleDescription> currentVersionModules, ClassList currentVersionClasses, ExcludeIncludeList currentEIList, String version,
                                      String baseline) {
          ModuleDescription unsupported =
                  currentVersionModules.get("jdk.unsupported");
  

*** 1928,10 ***
--- 1981,11 ---
          extraTask.accept(cm);
  
          ClassHeaderDescription headerDesc = new ClassHeaderDescription();
  
          headerDesc.flags = cm.flags().flagsMask();
+         headerDesc.preview = cm.minorVersion() == ClassFile.PREVIEW_MINOR_VERSION;
  
          if (cm.superclass().isPresent()) {
              headerDesc.extendsAttr = cm.superclass().get().asInternalName();
          }
          headerDesc.implementsAttr = cm.interfaces().stream().map(ClassEntry::asInternalName).collect(Collectors.toList());

*** 1994,10 ***
--- 2048,11 ---
  
          ModuleHeaderDescription headerDesc = new ModuleHeaderDescription();
  
          headerDesc.versions = version;
          headerDesc.flags = cm.flags().flagsMask();
+         headerDesc.preview = cm.minorVersion() == ClassFile.PREVIEW_MINOR_VERSION;
  
          for (var attr : cm.attributes()) {
              if (!readAttribute(headerDesc, attr))
                  return null;
          }

*** 2261,11 ***
              case ModuleMainClassAttribute a -> ((ModuleHeaderDescription) feature).moduleMainClass = a.mainClass().asInternalName();
              case RuntimeInvisibleTypeAnnotationsAttribute a ->
                  feature.classTypeAnnotations = typeAnnotations2Descriptions(a.annotations());
              case RuntimeVisibleTypeAnnotationsAttribute a ->
                  feature.runtimeTypeAnnotations = typeAnnotations2Descriptions(a.annotations());
!             default -> throw new IllegalArgumentException("Unhandled attribute: " + attr.attributeName()); // Do nothing
          }
  
          return true;
      }
  
--- 2316,17 ---
              case ModuleMainClassAttribute a -> ((ModuleHeaderDescription) feature).moduleMainClass = a.mainClass().asInternalName();
              case RuntimeInvisibleTypeAnnotationsAttribute a ->
                  feature.classTypeAnnotations = typeAnnotations2Descriptions(a.annotations());
              case RuntimeVisibleTypeAnnotationsAttribute a ->
                  feature.runtimeTypeAnnotations = typeAnnotations2Descriptions(a.annotations());
!             default -> {
+                 if (attr.attributeName().equalsString("LoadableDescriptors")) {
+                     //OK, do nothing
+                 } else {
+                     throw new IllegalArgumentException("Unhandled attribute: " + attr.attributeName());
+                 }
+             }
          }
  
          return true;
      }
  

*** 3306,15 ***
--- 3367,17 ---
          }
      }
  
      static abstract class HeaderDescription extends FeatureDescription {
          List<InnerClassInfo> innerClasses;
+         boolean preview;
  
          @Override
          public int hashCode() {
              int hash = super.hashCode();
              hash = 19 * hash + Objects.hashCode(this.innerClasses);
+             hash = 19 * hash + Objects.hashCode(this.preview);
              return hash;
          }
  
          @Override
          public boolean equals(Object obj) {

*** 3326,10 ***
--- 3389,13 ---
              }
              final HeaderDescription other = (HeaderDescription) obj;
              if (!listEquals(this.innerClasses, other.innerClasses)) {
                  return false;
              }
+             if (this.preview != other.preview) {
+                 return false;
+             }
              return true;
          }
  
          protected void writeInnerClasses(Appendable output,
                                           String baselineVersion,

*** 3364,10 ***
--- 3430,26 ---
  
                  reader.moveNext();
              }
          }
  
+         @Override
+         protected void writeAttributes(Appendable output) throws IOException {
+             super.writeAttributes(output);
+             if (preview) {
+                 output.append(" preview true");
+             }
+         }
+ 
+         @Override
+         protected void readAttributes(LineBasedReader reader) {
+             super.readAttributes(reader);
+             String inPreview = reader.attributes.get("preview");
+             if ("true".equals(inPreview)) {
+                 preview = true;
+             }
+         }
      }
  
      static class MethodDescription extends FeatureDescription {
          static int METHODS_FLAGS_NORMALIZATION = ~0;
          String name;
< prev index next >