Skip to content

Commit 66205e4

Browse files
Implement sealed class support
Change flags field in DynamicHub to short
1 parent 6cae92d commit 66205e4

File tree

5 files changed

+183
-6
lines changed

5 files changed

+183
-6
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.jdk17;
26+
27+
// Checkstyle: allow reflection
28+
29+
import com.oracle.svm.core.annotate.AutomaticFeature;
30+
import com.oracle.svm.core.jdk.SealedClassSupport;
31+
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
32+
import org.graalvm.nativeimage.ImageSingletons;
33+
import org.graalvm.nativeimage.hosted.Feature;
34+
35+
final class SealedClassSupportJDK17OrLater extends SealedClassSupport {
36+
37+
@Override
38+
public boolean isSealed(Class<?> clazz) {
39+
return clazz.isSealed();
40+
}
41+
42+
@Override
43+
public Class<?>[] getPermittedSubclasses(Class<?> clazz) {
44+
return clazz.getPermittedSubclasses();
45+
}
46+
}
47+
48+
@AutomaticFeature
49+
final class SealedClassFeatureJDK17OrLater implements Feature {
50+
@Override
51+
public boolean isInConfiguration(IsInConfigurationAccess access) {
52+
return JavaVersionUtil.JAVA_SPEC >= 17;
53+
}
54+
55+
@Override
56+
public void afterRegistration(AfterRegistrationAccess access) {
57+
ImageSingletons.add(SealedClassSupport.class, new SealedClassSupportJDK17OrLater());
58+
}
59+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 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
@@ -165,7 +165,7 @@ public final class DynamicHub implements JavaKind.FormatWithToString, AnnotatedE
165165
* field is final, so that various methods are constant folded for constant classes already
166166
* before the static analysis.
167167
*/
168-
private final byte flags;
168+
private final short flags;
169169

170170
/** Is this a primitive type. */
171171
private static final int IS_PRIMITIVE_FLAG_BIT = 0;
@@ -190,6 +190,11 @@ public final class DynamicHub implements JavaKind.FormatWithToString, AnnotatedE
190190
*/
191191
private static final int DECLARES_DEFAULT_METHODS_FLAG_BIT = 6;
192192

193+
/**
194+
* Is this a sealed Class.
195+
*/
196+
private static final int IS_SEALED_FLAG_BIT = 7;
197+
193198
/**
194199
* Has the type been discovered as instantiated by the static analysis?
195200
*/
@@ -276,6 +281,12 @@ public final class DynamicHub implements JavaKind.FormatWithToString, AnnotatedE
276281
*/
277282
private Object annotationsEncoding;
278283

284+
/**
285+
* Permitted subclasses for this class. This value is created during the image build by caching
286+
* Class.getPermittedSubclasses() value for usage in {@link DynamicHub#getPermittedSubclasses()}
287+
*/
288+
private Class<?>[] permittedSubclasses;
289+
279290
/**
280291
* Metadata for running class initializers at run time. Refers to a singleton marker object for
281292
* classes/interfaces already initialized during image generation, i.e., this field is never
@@ -344,7 +355,7 @@ public void setModule(Object module) {
344355

345356
@Platforms(Platform.HOSTED_ONLY.class)
346357
public DynamicHub(Class<?> hostedJavaClass, String name, HubType hubType, ReferenceType referenceType, Object isLocalClass, Object isAnonymousClass, DynamicHub superType, DynamicHub componentHub,
347-
String sourceFileName, int modifiers, ClassLoader classLoader, boolean isHidden, boolean isRecord, Class<?> nestHost, boolean assertionStatus,
358+
String sourceFileName, int modifiers, ClassLoader classLoader, boolean isHidden, boolean isRecord, boolean isSealed, Class<?> nestHost, boolean assertionStatus,
348359
boolean hasDefaultMethods, boolean declaresDefaultMethods) {
349360
this.hostedJavaClass = hostedJavaClass;
350361
this.name = name;
@@ -359,13 +370,14 @@ public DynamicHub(Class<?> hostedJavaClass, String name, HubType hubType, Refere
359370
this.classLoader = PredefinedClassesSupport.isPredefined(hostedJavaClass) ? NO_CLASS_LOADER : classLoader;
360371
this.nestHost = nestHost;
361372

362-
this.flags = NumUtil.safeToByte(makeFlag(IS_PRIMITIVE_FLAG_BIT, hostedJavaClass.isPrimitive()) |
373+
this.flags = NumUtil.safeToShort(makeFlag(IS_PRIMITIVE_FLAG_BIT, hostedJavaClass.isPrimitive()) |
363374
makeFlag(IS_INTERFACE_FLAG_BIT, hostedJavaClass.isInterface()) |
364375
makeFlag(IS_HIDDED_FLAG_BIT, isHidden) |
365376
makeFlag(IS_RECORD_FLAG_BIT, isRecord) |
366377
makeFlag(ASSERTION_STATUS_FLAG_BIT, assertionStatus) |
367378
makeFlag(HAS_DEFAULT_METHODS_FLAG_BIT, hasDefaultMethods) |
368-
makeFlag(DECLARES_DEFAULT_METHODS_FLAG_BIT, declaresDefaultMethods));
379+
makeFlag(DECLARES_DEFAULT_METHODS_FLAG_BIT, declaresDefaultMethods) |
380+
makeFlag(IS_SEALED_FLAG_BIT, isSealed));
369381
}
370382

371383
@Platforms(Platform.HOSTED_ONLY.class)
@@ -459,6 +471,11 @@ public Object getAnnotationsEncoding() {
459471
return annotationsEncoding;
460472
}
461473

474+
@Platforms(Platform.HOSTED_ONLY.class)
475+
public void setPermittedSubclasses(Class<?>[] permittedSubclasses) {
476+
this.permittedSubclasses = permittedSubclasses;
477+
}
478+
462479
@Platforms(Platform.HOSTED_ONLY.class)
463480
public boolean shouldInitEnumConstants() {
464481
return enumConstantsReference == null;
@@ -804,6 +821,12 @@ public boolean isRecord() {
804821
return isFlagSet(IS_RECORD_FLAG_BIT);
805822
}
806823

824+
@Substitute
825+
@TargetElement(onlyWith = JDK17OrLater.class)
826+
public boolean isSealed() {
827+
return isFlagSet(IS_SEALED_FLAG_BIT);
828+
}
829+
807830
@Substitute
808831
private boolean isLocalClass() {
809832
return booleanOrError(isLocalClass);
@@ -1216,6 +1239,12 @@ private Target_java_lang_reflect_RecordComponent[] getRecordComponents0() {
12161239
return (Target_java_lang_reflect_RecordComponent[]) result;
12171240
}
12181241

1242+
@Substitute
1243+
@TargetElement(onlyWith = JDK17OrLater.class)
1244+
private Class<?>[] getPermittedSubclasses() {
1245+
return permittedSubclasses;
1246+
}
1247+
12191248
@Substitute
12201249
@TargetElement(name = "checkMemberAccess", onlyWith = JDK8OrEarlier.class)
12211250
@SuppressWarnings("unused")
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.jdk;
26+
27+
// Checkstyle: allow reflection
28+
29+
import com.oracle.svm.core.annotate.AutomaticFeature;
30+
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
31+
import org.graalvm.nativeimage.ImageSingletons;
32+
import org.graalvm.nativeimage.Platform;
33+
import org.graalvm.nativeimage.Platforms;
34+
import org.graalvm.nativeimage.hosted.Feature;
35+
36+
/**
37+
* Abstracts the information about sealed classes, which are not available in Java 11 and Java 8.
38+
* This class provides all information about sealed classes without exposing any JDK types and
39+
* methods that are not yet present in the old JDKs.
40+
*/
41+
@Platforms(Platform.HOSTED_ONLY.class)
42+
public abstract class SealedClassSupport {
43+
44+
public static SealedClassSupport singleton() {
45+
return ImageSingletons.lookup(SealedClassSupport.class);
46+
}
47+
48+
/** Same as {@code Class.isSealed()}. */
49+
public abstract boolean isSealed(Class<?> clazz);
50+
51+
/** Same as {@code Class.permittedSubclasses()}. */
52+
public abstract Class<?>[] getPermittedSubclasses(Class<?> clazz);
53+
}
54+
55+
/**
56+
* Placeholder implementation for JDK versions that do not have sealed classes.
57+
*/
58+
final class SealedClassSupportJDK11OrEarlier extends SealedClassSupport {
59+
@Override
60+
public boolean isSealed(Class<?> clazz) {
61+
return false;
62+
}
63+
64+
@Override
65+
public Class<?>[] getPermittedSubclasses(Class<?> clazz) {
66+
return null;
67+
}
68+
}
69+
70+
@AutomaticFeature
71+
final class SealedClassFeatureBeforeJDK17 implements Feature {
72+
@Override
73+
public boolean isInConfiguration(IsInConfigurationAccess access) {
74+
return JavaVersionUtil.JAVA_SPEC <= 11;
75+
}
76+
77+
@Override
78+
public void afterRegistration(AfterRegistrationAccess access) {
79+
ImageSingletons.add(SealedClassSupport.class, new SealedClassSupportJDK11OrEarlier());
80+
}
81+
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.concurrent.CopyOnWriteArrayList;
4646
import java.util.function.BiConsumer;
4747

48+
import com.oracle.svm.core.jdk.SealedClassSupport;
4849
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
4950
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
5051
import org.graalvm.compiler.debug.MethodFilter;
@@ -402,11 +403,12 @@ private DynamicHub createHub(AnalysisType type) {
402403

403404
boolean isHidden = SubstrateUtil.isHiddenClass(javaClass);
404405
boolean isRecord = RecordSupport.singleton().isRecord(javaClass);
406+
boolean isSealed = SealedClassSupport.singleton().isSealed(javaClass);
405407
boolean assertionStatus = RuntimeAssertionsSupport.singleton().desiredAssertionStatus(javaClass);
406408

407409
final DynamicHub dynamicHub = new DynamicHub(javaClass, className, computeHubType(type), computeReferenceType(type),
408410
isLocalClass(javaClass), isAnonymousClass(javaClass), superHub, componentHub, sourceFileName,
409-
modifiers, hubClassLoader, isHidden, isRecord, nestHost, assertionStatus, type.hasDefaultMethods(), type.declaresDefaultMethods());
411+
modifiers, hubClassLoader, isHidden, isRecord, isSealed, nestHost, assertionStatus, type.hasDefaultMethods(), type.declaresDefaultMethods());
410412
if (JavaVersionUtil.JAVA_SPEC > 8) {
411413
ModuleAccess.extractAndSetModule(dynamicHub, javaClass);
412414
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.oracle.svm.core.hub.AnnotatedSuperInfo;
4444
import com.oracle.svm.core.hub.DynamicHub;
4545
import com.oracle.svm.core.hub.GenericInfo;
46+
import com.oracle.svm.core.jdk.SealedClassSupport;
4647
import com.oracle.svm.core.meta.SubstrateObjectConstant;
4748
import com.oracle.svm.hosted.SVMHost;
4849

@@ -103,6 +104,11 @@ public void initializeMetaData(AnalysisType type) {
103104
fillInterfaces(type, hub);
104105
}
105106

107+
/*
108+
* Support for permitted subclasses of a sealed class.
109+
*/
110+
hub.setPermittedSubclasses(SealedClassSupport.singleton().getPermittedSubclasses(type.getJavaClass()));
111+
106112
/*
107113
* Support for Java annotations.
108114
*/

0 commit comments

Comments
 (0)