Skip to content
Permalink
Browse files
8260517: implement Sealed Classes as a standard feature in Java
Co-authored-by: Harold Seigel <hseigel@openjdk.org>
Co-authored-by: Vicente Romero <vromero@openjdk.org>
Reviewed-by: dholmes, mcimadamore, jlahoda
  • Loading branch information
Vicente Romero and Harold Seigel committed May 20, 2021
1 parent 31b98e1 commit 0fa9223f34bc33635079763362f42f0a5c53759b
Showing with 169 additions and 393 deletions.
  1. +39 −0 make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
  2. +3 −9 src/hotspot/share/classfile/classFileParser.cpp
  3. +0 −3 src/hotspot/share/classfile/classFileParser.hpp
  4. +2 −2 src/hotspot/share/include/jvm.h
  5. +4 −6 src/java.base/share/classes/java/lang/Class.java
  6. +3 −0 src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java
  7. +1 −3 src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java
  8. +1 −5 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
  9. +1 −2 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
  10. +1 −2 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
  11. +1 −2 src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
  12. +2 −2 test/hotspot/jtreg/runtime/modules/SealedInterfaceModuleTest.java
  13. +2 −2 test/hotspot/jtreg/runtime/modules/SealedModuleTest.java
  14. +2 −2 test/hotspot/jtreg/runtime/modules/sealedP1/SuperClass.jcod
  15. +2 −2 test/hotspot/jtreg/runtime/modules/sealedP1/SuperInterface.jcod
  16. +0 −45 test/hotspot/jtreg/runtime/sealedClasses/AbstractSealedTest.java
  17. +8 −8 test/hotspot/jtreg/runtime/sealedClasses/GetPermittedSubclasses.jcod
  18. +4 −5 test/hotspot/jtreg/runtime/sealedClasses/GetPermittedSubclassesTest.java
  19. +1 −3 test/hotspot/jtreg/runtime/sealedClasses/OverrideSealedTest.java
  20. +2 −2 test/hotspot/jtreg/runtime/sealedClasses/Pkg/SealedInterface.jcod
  21. +4 −5 test/hotspot/jtreg/runtime/sealedClasses/RedefinePermittedSubclass.java
  22. +4 −5 test/hotspot/jtreg/runtime/sealedClasses/RedefineSealedClass.java
  23. +0 −49 test/hotspot/jtreg/runtime/sealedClasses/SealedTest.java
  24. +3 −3 test/hotspot/jtreg/runtime/sealedClasses/SealedUnnamedModuleIntfTest.java
  25. +3 −3 test/hotspot/jtreg/runtime/sealedClasses/SealedUnnamedModuleTest.java
  26. +2 −2 test/hotspot/jtreg/runtime/sealedClasses/planets/OuterPlanets.jcod
  27. +11 −14 test/jdk/java/lang/instrument/RedefinePermittedSubclassesAttr/TestPermittedSubclassesAttr.java
  28. +3 −0 test/langtools/tools/javac/diags/examples.not-yet.txt
  29. +1 −4 test/langtools/tools/javac/diags/examples/AnonymousCantInheritFromSealed.java
  30. +1 −3 ...s/tools/javac/diags/examples/CantExtendSealedInAnotherModule/CantExtendSealedInAnotherModule.java
  31. +0 −3 ...ngtools/tools/javac/diags/examples/CantExtendSealedInAnotherPkg/CantExtendSealedInAnotherPkg.java
  32. +1 −4 test/langtools/tools/javac/diags/examples/CantInheritFromSealed.java
  33. +1 −4 test/langtools/tools/javac/diags/examples/CantInheritFromSealed2.java
  34. +1 −4 test/langtools/tools/javac/diags/examples/DuplicateTypeInPermits.java
  35. +1 −4 test/langtools/tools/javac/diags/examples/LocalCantInheritFromSealed.java
  36. +1 −4 test/langtools/tools/javac/diags/examples/NonSealedWithNoSealedSuper.java
  37. +1 −4 test/langtools/tools/javac/diags/examples/PermitsCantListDeclaringClass.java
  38. +1 −4 test/langtools/tools/javac/diags/examples/PermitsCantListSuperType.java
  39. +1 −4 test/langtools/tools/javac/diags/examples/PermitsInNoSealedClass.java
  40. +1 −4 test/langtools/tools/javac/diags/examples/SealedMustHaveSubtypes.java
  41. +1 −4 test/langtools/tools/javac/diags/examples/SealedNotAllowedInLocalClass.java
  42. +3 −3 test/langtools/tools/javac/diags/examples/SealedTypes.java
  43. +1 −4 test/langtools/tools/javac/diags/examples/SubtypeDoesntExtendSealed.java
  44. +1 −4 test/langtools/tools/javac/diags/examples/TypeVarInPermits.java
  45. +0 −5 test/langtools/tools/javac/preview/DeclaredUsingPreview-class.out
  46. +0 −7 test/langtools/tools/javac/preview/DeclaredUsingPreview-source.out
  47. +0 −11 test/langtools/tools/javac/preview/DeclaredUsingPreview.java
  48. +0 −5 test/langtools/tools/javac/preview/DeclaredUsingPreviewDeclarations.java
  49. +4 −9 test/langtools/tools/javac/preview/PreviewAutoSuppress.java
  50. +15 −38 test/langtools/tools/javac/preview/PreviewErrors.java
  51. +2 −7 test/langtools/tools/javac/processing/model/element/TestSealed.java
  52. +4 −31 test/langtools/tools/javac/sealed/SealedCompilationTests.java
  53. +18 −32 test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java
  54. +0 −1 test/langtools/tools/jdeps/listdeps/ListModuleDeps.java
@@ -132,6 +132,7 @@
import com.sun.tools.classfile.Module_attribute.RequiresEntry;
import com.sun.tools.classfile.NestHost_attribute;
import com.sun.tools.classfile.NestMembers_attribute;
import com.sun.tools.classfile.PermittedSubclasses_attribute;
import com.sun.tools.classfile.Record_attribute;
import com.sun.tools.classfile.Record_attribute.ComponentInfo;
import com.sun.tools.classfile.RuntimeAnnotations_attribute;
@@ -978,6 +979,16 @@ private void addAttributes(ClassHeaderDescription header,
attributes.put(Attribute.Record,
new Record_attribute(attributeString, recordComponents));
}
if (header.isSealed) {
int attributeString = addString(constantPool, Attribute.PermittedSubclasses);
int[] subclasses = new int[header.permittedSubclasses.size()];
int i = 0;
for (String intf : header.permittedSubclasses) {
subclasses[i++] = addClass(constantPool, intf);
}
attributes.put(Attribute.PermittedSubclasses,
new PermittedSubclasses_attribute(attributeString, subclasses));
}
addInnerClassesAttribute(header, constantPool, attributes);
}

@@ -2229,6 +2240,16 @@ private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribut
}
break;
}
case Attribute.PermittedSubclasses: {
assert feature instanceof ClassHeaderDescription;
PermittedSubclasses_attribute permittedSubclasses = (PermittedSubclasses_attribute) attr;
ClassHeaderDescription chd = (ClassHeaderDescription) feature;
chd.permittedSubclasses = Arrays.stream(permittedSubclasses.subtypes)
.mapToObj(i -> getClassName(cf, i))
.collect(Collectors.toList());
chd.isSealed = true;
break;
}
default:
throw new IllegalStateException("Unhandled attribute: " +
attrName);
@@ -3077,6 +3098,8 @@ public String packge() {
List<String> nestMembers;
boolean isRecord;
List<RecordComponentDescription> recordComponents;
boolean isSealed;
List<String> permittedSubclasses;

@Override
public int hashCode() {
@@ -3087,6 +3110,8 @@ public int hashCode() {
hash = 17 * hash + Objects.hashCode(this.nestMembers);
hash = 17 * hash + Objects.hashCode(this.isRecord);
hash = 17 * hash + Objects.hashCode(this.recordComponents);
hash = 17 * hash + Objects.hashCode(this.isSealed);
hash = 17 * hash + Objects.hashCode(this.permittedSubclasses);
return hash;
}

@@ -3117,6 +3142,12 @@ public boolean equals(Object obj) {
if (!listEquals(this.recordComponents, other.recordComponents)) {
return false;
}
if (this.isSealed != other.isSealed) {
return false;
}
if (!listEquals(this.permittedSubclasses, other.permittedSubclasses)) {
return false;
}
return true;
}

@@ -3137,6 +3168,9 @@ public void write(Appendable output, String baselineVersion, String version) thr
if (isRecord) {
output.append(" record true");
}
if (isSealed) {
output.append(" sealed true");
}
writeAttributes(output);
output.append("\n");
writeRecordComponents(output, baselineVersion, version);
@@ -3163,6 +3197,11 @@ public boolean read(LineBasedReader reader) throws IOException {
readRecordComponents(reader);
}
readInnerClasses(reader);
isSealed = reader.attributes.containsKey("permittedSubclasses");
if (isSealed) {
String subclassesList = reader.attributes.get("permittedSubclasses");
permittedSubclasses = deserializeList(subclassesList);
}

return true;
}
@@ -3532,12 +3532,6 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
CHECK);
}

bool ClassFileParser::supports_sealed_types() {
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
Arguments::enable_preview();
}

void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
ConstantPool* cp,
ClassFileParser::ClassAnnotationCollector* parsed_annotations,
@@ -3794,8 +3788,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
parsed_record_attribute = true;
record_attribute_start = cfs->current();
record_attribute_length = attribute_length;
} else if (tag == vmSymbols::tag_permitted_subclasses()) {
if (supports_sealed_types()) {
} else if (_major_version >= JAVA_17_VERSION) {
if (tag == vmSymbols::tag_permitted_subclasses()) {
if (parsed_permitted_subclasses_attribute) {
classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", CHECK);
return;
@@ -3810,7 +3804,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
permitted_subclasses_attribute_length = attribute_length;
}
}
// Skip attribute_length for any attribute where major_verson >= JAVA_16_VERSION
// Skip attribute_length for any attribute where major_verson >= JAVA_17_VERSION
cfs->skip_u1(attribute_length, CHECK);
} else {
// Unknown attribute
@@ -333,9 +333,6 @@ class ClassFileParser {
const u1* const record_attribute_start,
TRAPS);

bool supports_sealed_types();
bool supports_records();

void parse_classfile_attributes(const ClassFileStream* const cfs,
ConstantPool* cp,
ClassAnnotationCollector* parsed_annotations,
@@ -606,15 +606,15 @@ JVM_GetNestHost(JNIEnv *env, jclass current);
JNIEXPORT jobjectArray JNICALL
JVM_GetNestMembers(JNIEnv *env, jclass current);

/* Records - since JDK 14 */
/* Records - since JDK 16 */

JNIEXPORT jboolean JNICALL
JVM_IsRecord(JNIEnv *env, jclass cls);

JNIEXPORT jobjectArray JNICALL
JVM_GetRecordComponents(JNIEnv *env, jclass ofClass);

/* Sealed types - since JDK 15 */
/* Sealed classes - since JDK 17 */

JNIEXPORT jobjectArray JNICALL
JVM_GetPermittedSubclasses(JNIEnv *env, jclass current);
@@ -4475,9 +4475,8 @@ public String descriptorString() {
*
* @jls 8.1 Class Declarations
* @jls 9.1 Interface Declarations
* @since 15
* @since 17
*/
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.SEALED_CLASSES, reflective=true)
@CallerSensitive
public Class<?>[] getPermittedSubclasses() {
Class<?>[] subClasses;
@@ -4524,14 +4523,13 @@ private boolean isDirectSubType(Class<?> c) {
* subclasses; {@link #getPermittedSubclasses()} returns a non-null but
* possibly empty value for a sealed class or interface.
*
* @return {@code true} if and only if this {@code Class} object represents a sealed class or interface.
* @return {@code true} if and only if this {@code Class} object represents
* a sealed class or interface.
*
* @jls 8.1 Class Declarations
* @jls 9.1 Interface Declarations
* @since 15
* @since 17
*/
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.SEALED_CLASSES, reflective=true)
@SuppressWarnings("preview")
public boolean isSealed() {
if (isArray() || isPrimitive()) {
return false;
@@ -54,6 +54,9 @@
public boolean reflective() default false;

public enum Feature {
/*
* This one can only be removed after JDK 17
*/
SEALED_CLASSES,
/**
* A key for testing.
@@ -93,10 +93,8 @@
*
* @return the subclasses
*
* @since 15
* @since 17
*/
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.SEALED_CLASSES,
reflective=true)
default List<? extends Tree> getPermitsClause() {
return List.of();
}
@@ -183,8 +183,6 @@ public boolean isEnabled() {
*/
public boolean isPreview(Feature feature) {
return switch (feature) {
case SEALED_CLASSES -> true;

//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true'
//for those selected features, and 'false' for all the others.
@@ -224,9 +222,7 @@ public Error disabledError(JavaFileObject classfile, int majorVersion) {
* @return true iff sym has been declared using a preview language feature
*/
public boolean declaredUsingPreviewFeature(Symbol sym) {
return ((sym.flags() & RECORD) != 0 && isPreview(Feature.RECORDS)) ||
((sym.flags() & SEALED) != 0 && isPreview(Feature.SEALED_CLASSES)) ||
((sym.flags() & NON_SEALED) != 0 && isPreview(Feature.SEALED_CLASSES));
return false;
}

/**
@@ -161,8 +161,7 @@ protected Check(Context context) {
deferredLintHandler = DeferredLintHandler.instance(context);

allowRecords = Feature.RECORDS.allowedInSource(source);
allowSealed = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
Feature.SEALED_CLASSES.allowedInSource(source);
allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
}

/** Character for synthetic names
@@ -278,8 +278,7 @@ protected ClassReader(Context context) {
preview = Preview.instance(context);
allowModules = Feature.MODULES.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
Feature.SEALED_CLASSES.allowedInSource(source);
allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);

saveParameterNames = options.isSet(PARAMETERS);

@@ -186,8 +186,7 @@ protected JavacParser(ParserFactory fac,
this.allowYieldStatement = (!preview.isPreview(Feature.SWITCH_EXPRESSION) || preview.isEnabled()) &&
Feature.SWITCH_EXPRESSION.allowedInSource(source);
this.allowRecords = Feature.RECORDS.allowedInSource(source);
this.allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
Feature.SEALED_CLASSES.allowedInSource(source);
this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
}

protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
@@ -27,11 +27,11 @@
* @modules java.base/jdk.internal.misc
* @library /test/lib ..
* @compile sealedP1/SuperInterface.jcod
* @compile --enable-preview --source ${jdk.version} sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
* @compile sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
* @build sun.hotspot.WhiteBox
* @compile/module=java.base java/lang/ModuleHelper.java
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedInterfaceModuleTest
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedInterfaceModuleTest
*/

public class SealedInterfaceModuleTest {
@@ -27,11 +27,11 @@
* @modules java.base/jdk.internal.misc
* @library /test/lib ..
* @compile sealedP1/SuperClass.jcod
* @compile --enable-preview --source ${jdk.version} sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
* @compile sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
* @build sun.hotspot.WhiteBox
* @compile/module=java.base java/lang/ModuleHelper.java
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedModuleTest
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedModuleTest
*/

public class SealedModuleTest {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@

class sealedP1/SuperClass {
0xCAFEBABE;
65535; // minor version
0; // minor version
61; // version
[20] { // Constant Pool
; // first element is empty
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
//
class sealedP1/SuperInterface {
0xCAFEBABE;
65535; // minor version
0; // minor version
61; // version
[14] { // Constant Pool
; // first element is empty

This file was deleted.

0 comments on commit 0fa9223

Please sign in to comment.