Skip to content

Commit 0fa9223

Browse files
Vicente RomeroHarold Seigel
Vicente Romero
and
Harold Seigel
committed
8260517: implement Sealed Classes as a standard feature in Java
Co-authored-by: Harold Seigel <[email protected]> Co-authored-by: Vicente Romero <[email protected]> Reviewed-by: dholmes, mcimadamore, jlahoda
1 parent 31b98e1 commit 0fa9223

File tree

54 files changed

+169
-393
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+169
-393
lines changed

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
import com.sun.tools.classfile.Module_attribute.RequiresEntry;
133133
import com.sun.tools.classfile.NestHost_attribute;
134134
import com.sun.tools.classfile.NestMembers_attribute;
135+
import com.sun.tools.classfile.PermittedSubclasses_attribute;
135136
import com.sun.tools.classfile.Record_attribute;
136137
import com.sun.tools.classfile.Record_attribute.ComponentInfo;
137138
import com.sun.tools.classfile.RuntimeAnnotations_attribute;
@@ -978,6 +979,16 @@ private void addAttributes(ClassHeaderDescription header,
978979
attributes.put(Attribute.Record,
979980
new Record_attribute(attributeString, recordComponents));
980981
}
982+
if (header.isSealed) {
983+
int attributeString = addString(constantPool, Attribute.PermittedSubclasses);
984+
int[] subclasses = new int[header.permittedSubclasses.size()];
985+
int i = 0;
986+
for (String intf : header.permittedSubclasses) {
987+
subclasses[i++] = addClass(constantPool, intf);
988+
}
989+
attributes.put(Attribute.PermittedSubclasses,
990+
new PermittedSubclasses_attribute(attributeString, subclasses));
991+
}
981992
addInnerClassesAttribute(header, constantPool, attributes);
982993
}
983994

@@ -2229,6 +2240,16 @@ private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribut
22292240
}
22302241
break;
22312242
}
2243+
case Attribute.PermittedSubclasses: {
2244+
assert feature instanceof ClassHeaderDescription;
2245+
PermittedSubclasses_attribute permittedSubclasses = (PermittedSubclasses_attribute) attr;
2246+
ClassHeaderDescription chd = (ClassHeaderDescription) feature;
2247+
chd.permittedSubclasses = Arrays.stream(permittedSubclasses.subtypes)
2248+
.mapToObj(i -> getClassName(cf, i))
2249+
.collect(Collectors.toList());
2250+
chd.isSealed = true;
2251+
break;
2252+
}
22322253
default:
22332254
throw new IllegalStateException("Unhandled attribute: " +
22342255
attrName);
@@ -3077,6 +3098,8 @@ static class ClassHeaderDescription extends HeaderDescription {
30773098
List<String> nestMembers;
30783099
boolean isRecord;
30793100
List<RecordComponentDescription> recordComponents;
3101+
boolean isSealed;
3102+
List<String> permittedSubclasses;
30803103

30813104
@Override
30823105
public int hashCode() {
@@ -3087,6 +3110,8 @@ public int hashCode() {
30873110
hash = 17 * hash + Objects.hashCode(this.nestMembers);
30883111
hash = 17 * hash + Objects.hashCode(this.isRecord);
30893112
hash = 17 * hash + Objects.hashCode(this.recordComponents);
3113+
hash = 17 * hash + Objects.hashCode(this.isSealed);
3114+
hash = 17 * hash + Objects.hashCode(this.permittedSubclasses);
30903115
return hash;
30913116
}
30923117

@@ -3117,6 +3142,12 @@ public boolean equals(Object obj) {
31173142
if (!listEquals(this.recordComponents, other.recordComponents)) {
31183143
return false;
31193144
}
3145+
if (this.isSealed != other.isSealed) {
3146+
return false;
3147+
}
3148+
if (!listEquals(this.permittedSubclasses, other.permittedSubclasses)) {
3149+
return false;
3150+
}
31203151
return true;
31213152
}
31223153

@@ -3137,6 +3168,9 @@ public void write(Appendable output, String baselineVersion, String version) thr
31373168
if (isRecord) {
31383169
output.append(" record true");
31393170
}
3171+
if (isSealed) {
3172+
output.append(" sealed true");
3173+
}
31403174
writeAttributes(output);
31413175
output.append("\n");
31423176
writeRecordComponents(output, baselineVersion, version);
@@ -3163,6 +3197,11 @@ public boolean read(LineBasedReader reader) throws IOException {
31633197
readRecordComponents(reader);
31643198
}
31653199
readInnerClasses(reader);
3200+
isSealed = reader.attributes.containsKey("permittedSubclasses");
3201+
if (isSealed) {
3202+
String subclassesList = reader.attributes.get("permittedSubclasses");
3203+
permittedSubclasses = deserializeList(subclassesList);
3204+
}
31663205

31673206
return true;
31683207
}

src/hotspot/share/classfile/classFileParser.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3532,12 +3532,6 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
35323532
CHECK);
35333533
}
35343534

3535-
bool ClassFileParser::supports_sealed_types() {
3536-
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
3537-
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
3538-
Arguments::enable_preview();
3539-
}
3540-
35413535
void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
35423536
ConstantPool* cp,
35433537
ClassFileParser::ClassAnnotationCollector* parsed_annotations,
@@ -3794,8 +3788,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
37943788
parsed_record_attribute = true;
37953789
record_attribute_start = cfs->current();
37963790
record_attribute_length = attribute_length;
3797-
} else if (tag == vmSymbols::tag_permitted_subclasses()) {
3798-
if (supports_sealed_types()) {
3791+
} else if (_major_version >= JAVA_17_VERSION) {
3792+
if (tag == vmSymbols::tag_permitted_subclasses()) {
37993793
if (parsed_permitted_subclasses_attribute) {
38003794
classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", CHECK);
38013795
return;
@@ -3810,7 +3804,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
38103804
permitted_subclasses_attribute_length = attribute_length;
38113805
}
38123806
}
3813-
// Skip attribute_length for any attribute where major_verson >= JAVA_16_VERSION
3807+
// Skip attribute_length for any attribute where major_verson >= JAVA_17_VERSION
38143808
cfs->skip_u1(attribute_length, CHECK);
38153809
} else {
38163810
// Unknown attribute

src/hotspot/share/classfile/classFileParser.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,9 +333,6 @@ class ClassFileParser {
333333
const u1* const record_attribute_start,
334334
TRAPS);
335335

336-
bool supports_sealed_types();
337-
bool supports_records();
338-
339336
void parse_classfile_attributes(const ClassFileStream* const cfs,
340337
ConstantPool* cp,
341338
ClassAnnotationCollector* parsed_annotations,

src/hotspot/share/include/jvm.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,15 +606,15 @@ JVM_GetNestHost(JNIEnv *env, jclass current);
606606
JNIEXPORT jobjectArray JNICALL
607607
JVM_GetNestMembers(JNIEnv *env, jclass current);
608608

609-
/* Records - since JDK 14 */
609+
/* Records - since JDK 16 */
610610

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

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

617-
/* Sealed types - since JDK 15 */
617+
/* Sealed classes - since JDK 17 */
618618

619619
JNIEXPORT jobjectArray JNICALL
620620
JVM_GetPermittedSubclasses(JNIEnv *env, jclass current);

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4475,9 +4475,8 @@ public Optional<ClassDesc> describeConstable() {
44754475
*
44764476
* @jls 8.1 Class Declarations
44774477
* @jls 9.1 Interface Declarations
4478-
* @since 15
4478+
* @since 17
44794479
*/
4480-
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.SEALED_CLASSES, reflective=true)
44814480
@CallerSensitive
44824481
public Class<?>[] getPermittedSubclasses() {
44834482
Class<?>[] subClasses;
@@ -4524,14 +4523,13 @@ private boolean isDirectSubType(Class<?> c) {
45244523
* subclasses; {@link #getPermittedSubclasses()} returns a non-null but
45254524
* possibly empty value for a sealed class or interface.
45264525
*
4527-
* @return {@code true} if and only if this {@code Class} object represents a sealed class or interface.
4526+
* @return {@code true} if and only if this {@code Class} object represents
4527+
* a sealed class or interface.
45284528
*
45294529
* @jls 8.1 Class Declarations
45304530
* @jls 9.1 Interface Declarations
4531-
* @since 15
4531+
* @since 17
45324532
*/
4533-
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.SEALED_CLASSES, reflective=true)
4534-
@SuppressWarnings("preview")
45354533
public boolean isSealed() {
45364534
if (isArray() || isPrimitive()) {
45374535
return false;

src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
public boolean reflective() default false;
5555

5656
public enum Feature {
57+
/*
58+
* This one can only be removed after JDK 17
59+
*/
5760
SEALED_CLASSES,
5861
/**
5962
* A key for testing.

src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,8 @@ public interface ClassTree extends StatementTree {
9393
*
9494
* @return the subclasses
9595
*
96-
* @since 15
96+
* @since 17
9797
*/
98-
@jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.SEALED_CLASSES,
99-
reflective=true)
10098
default List<? extends Tree> getPermitsClause() {
10199
return List.of();
102100
}

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,6 @@ public boolean isEnabled() {
183183
*/
184184
public boolean isPreview(Feature feature) {
185185
return switch (feature) {
186-
case SEALED_CLASSES -> true;
187-
188186
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
189187
//When real preview features will be added, this method can be implemented to return 'true'
190188
//for those selected features, and 'false' for all the others.
@@ -224,9 +222,7 @@ public Error disabledError(JavaFileObject classfile, int majorVersion) {
224222
* @return true iff sym has been declared using a preview language feature
225223
*/
226224
public boolean declaredUsingPreviewFeature(Symbol sym) {
227-
return ((sym.flags() & RECORD) != 0 && isPreview(Feature.RECORDS)) ||
228-
((sym.flags() & SEALED) != 0 && isPreview(Feature.SEALED_CLASSES)) ||
229-
((sym.flags() & NON_SEALED) != 0 && isPreview(Feature.SEALED_CLASSES));
225+
return false;
230226
}
231227

232228
/**

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,7 @@ protected Check(Context context) {
161161
deferredLintHandler = DeferredLintHandler.instance(context);
162162

163163
allowRecords = Feature.RECORDS.allowedInSource(source);
164-
allowSealed = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
165-
Feature.SEALED_CLASSES.allowedInSource(source);
164+
allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
166165
}
167166

168167
/** Character for synthetic names

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,7 @@ protected ClassReader(Context context) {
278278
preview = Preview.instance(context);
279279
allowModules = Feature.MODULES.allowedInSource(source);
280280
allowRecords = Feature.RECORDS.allowedInSource(source);
281-
allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
282-
Feature.SEALED_CLASSES.allowedInSource(source);
281+
allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
283282

284283
saveParameterNames = options.isSet(PARAMETERS);
285284

src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,7 @@ protected JavacParser(ParserFactory fac,
186186
this.allowYieldStatement = (!preview.isPreview(Feature.SWITCH_EXPRESSION) || preview.isEnabled()) &&
187187
Feature.SWITCH_EXPRESSION.allowedInSource(source);
188188
this.allowRecords = Feature.RECORDS.allowedInSource(source);
189-
this.allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
190-
Feature.SEALED_CLASSES.allowedInSource(source);
189+
this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
191190
}
192191

193192
protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {

test/hotspot/jtreg/runtime/modules/SealedInterfaceModuleTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
* @modules java.base/jdk.internal.misc
2828
* @library /test/lib ..
2929
* @compile sealedP1/SuperInterface.jcod
30-
* @compile --enable-preview --source ${jdk.version} sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
30+
* @compile sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
3131
* @build sun.hotspot.WhiteBox
3232
* @compile/module=java.base java/lang/ModuleHelper.java
3333
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
34-
* @run main/othervm -Xbootclasspath/a:. --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedInterfaceModuleTest
34+
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedInterfaceModuleTest
3535
*/
3636

3737
public class SealedInterfaceModuleTest {

test/hotspot/jtreg/runtime/modules/SealedModuleTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
* @modules java.base/jdk.internal.misc
2828
* @library /test/lib ..
2929
* @compile sealedP1/SuperClass.jcod
30-
* @compile --enable-preview --source ${jdk.version} sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
30+
* @compile sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
3131
* @build sun.hotspot.WhiteBox
3232
* @compile/module=java.base java/lang/ModuleHelper.java
3333
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
34-
* @run main/othervm -Xbootclasspath/a:. --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedModuleTest
34+
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedModuleTest
3535
*/
3636

3737
public class SealedModuleTest {

test/hotspot/jtreg/runtime/modules/sealedP1/SuperClass.jcod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
3232

3333
class sealedP1/SuperClass {
3434
0xCAFEBABE;
35-
65535; // minor version
35+
0; // minor version
3636
61; // version
3737
[20] { // Constant Pool
3838
; // first element is empty

test/hotspot/jtreg/runtime/modules/sealedP1/SuperInterface.jcod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
3232
//
3333
class sealedP1/SuperInterface {
3434
0xCAFEBABE;
35-
65535; // minor version
35+
0; // minor version
3636
61; // version
3737
[14] { // Constant Pool
3838
; // first element is empty

test/hotspot/jtreg/runtime/sealedClasses/AbstractSealedTest.java

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)