Skip to content

Commit 65bff40

Browse files
author
Lukáš Rozsypal
committed
[GR-58042] Add subtyping to @AutomaticallyRegisteredImageSingleton-generated Features
PullRequest: graal/18782
2 parents e87cf66 + 715a8fe commit 65bff40

File tree

4 files changed

+57
-24
lines changed

4 files changed

+57
-24
lines changed

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxThreadCpuTimeSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import com.oracle.svm.core.util.TimeUtils;
4343

4444
@AutomaticallyRegisteredImageSingleton(ThreadCpuTimeSupport.class)
45-
final class LinuxThreadCpuTimeSupport implements ThreadCpuTimeSupport {
45+
public class LinuxThreadCpuTimeSupport implements ThreadCpuTimeSupport {
4646

4747
@Override
4848
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/feature/AutomaticallyRegisteredImageSingleton.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
* annotated class must not rely on other features being registered already, or other image
4646
* singletons being present already.
4747
*
48+
* If both a class and a subclass are annotated with {@link AutomaticallyRegisteredImageSingleton}
49+
* (and the subclass is not disabled by {@link #onlyWith}), only the subclass will be registered as
50+
* an image singleton.
51+
*
4852
* The requirements and restrictions of {@link AutomaticallyRegisteredFeature} apply also to this
4953
* annotation.
5054
*/
@@ -54,14 +58,17 @@
5458
public @interface AutomaticallyRegisteredImageSingleton {
5559

5660
/**
57-
* The keys under which the singleton is registered in {@link ImageSingletons}. If no keys are
58-
* specified, the annotated class itself is used as the key.
61+
* The keys under which the singleton is registered in {@link ImageSingletons}. If the annotated
62+
* class extends another annotated class, keys from the base class are inherited. If no keys are
63+
* specified (or inherited), the annotated class itself is used as the key.
5964
*/
6065
Class<?>[] value() default {};
6166

6267
/**
6368
* Register only if all provided {@link BooleanSupplier} objects evaluate to true. If there are
6469
* no suppliers, the singleton is registered unconditionally.
70+
*
71+
* The values of this attribute are not inherited; a subclass may have fewer restrictions.
6572
*/
6673
Class<? extends BooleanSupplier>[] onlyWith() default {};
6774
}
Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,19 @@
2626

2727
import java.nio.file.Path;
2828

29-
import org.graalvm.nativeimage.ImageSingletons;
3029
import org.graalvm.nativeimage.Platform;
3130
import org.graalvm.nativeimage.Platforms;
3231
import org.graalvm.nativeimage.impl.InternalPlatform;
3332

34-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
35-
import com.oracle.svm.core.feature.InternalFeature;
33+
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
3634

3735
@Platforms(InternalPlatform.PLATFORM_JNI.class)
38-
@AutomaticallyRegisteredFeature
39-
public final class JDKLibDirectoryFeature implements InternalFeature {
36+
@AutomaticallyRegisteredImageSingleton(JDKLibDirectoryProvider.class)
37+
public class HostJDKLibDirectoryProvider implements JDKLibDirectoryProvider {
4038
@Override
41-
public void duringSetup(DuringSetupAccess access) {
42-
if (!ImageSingletons.contains(JDKLibDirectoryProvider.class)) {
43-
ImageSingletons.add(JDKLibDirectoryProvider.class, new HostJDKLibDirectoryProvider());
44-
}
45-
}
46-
47-
private static final class HostJDKLibDirectoryProvider implements JDKLibDirectoryProvider {
48-
@Override
49-
public Path getJDKLibDirectory() {
50-
/* On Windows, JDK libraries are in `<java.home>\bin` directory. */
51-
boolean isWindows = Platform.includedIn(Platform.WINDOWS.class);
52-
return Path.of(System.getProperty("java.home"), isWindows ? "bin" : "lib");
53-
}
39+
public Path getJDKLibDirectory() {
40+
/* On Windows, JDK libraries are in `<java.home>\bin` directory. */
41+
boolean isWindows = Platform.includedIn(Platform.WINDOWS.class);
42+
return Path.of(System.getProperty("java.home"), isWindows ? "bin" : "lib");
5443
}
5544
}

substratevm/src/com.oracle.svm.processor/src/com/oracle/svm/processor/AutomaticallyRegisteredImageSingletonProcessor.java

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2024, 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
@@ -25,6 +25,7 @@
2525
package com.oracle.svm.processor;
2626

2727
import java.io.PrintWriter;
28+
import java.util.ArrayList;
2829
import java.util.HashSet;
2930
import java.util.List;
3031
import java.util.Set;
@@ -35,6 +36,8 @@
3536
import javax.lang.model.element.AnnotationMirror;
3637
import javax.lang.model.element.Element;
3738
import javax.lang.model.element.TypeElement;
39+
import javax.lang.model.type.DeclaredType;
40+
import javax.lang.model.type.TypeKind;
3841
import javax.lang.model.type.TypeMirror;
3942

4043
import jdk.graal.compiler.processor.AbstractProcessor;
@@ -83,21 +86,32 @@ private void processElement(TypeElement annotatedType) {
8386
out.println("@Platforms({" + platforms + "})");
8487
}
8588
out.println("@" + getSimpleName(AutomaticallyRegisteredFeatureProcessor.ANNOTATION_CLASS_NAME));
86-
out.println("public final class " + featureClassName + " implements " +
87-
String.join(", ", new String[]{AutomaticallyRegisteredFeatureProcessor.FEATURE_INTERFACE_CLASS_NAME, FEATURE_SINGLETON_NAME, UNSAVED_SINGLETON_NAME}) + " {");
89+
List<TypeElement> singletonSuperclasses = getSingletonSuperclasses(annotatedType);
90+
String supertypes = singletonSuperclasses.isEmpty()
91+
? " implements " + String.join(", ", new String[]{AutomaticallyRegisteredFeatureProcessor.FEATURE_INTERFACE_CLASS_NAME, FEATURE_SINGLETON_NAME, UNSAVED_SINGLETON_NAME})
92+
: " extends " + getPackage(singletonSuperclasses.get(0)).getQualifiedName().toString() + "." + getTypeNameWithEnclosingClasses(singletonSuperclasses.get(0), "Feature");
93+
out.println("public class " + featureClassName + supertypes + " {");
8894
out.println(" @Override");
8995
out.println(" public void afterRegistration(AfterRegistrationAccess access) {");
9096

9197
List<TypeMirror> onlyWithList = getAnnotationValueList(singletonAnnotation, "onlyWith", TypeMirror.class);
9298
if (!onlyWithList.isEmpty()) {
9399
for (var onlyWith : onlyWithList) {
94100
out.println(" if (!new " + onlyWith + "().getAsBoolean()) {");
101+
if (!singletonSuperclasses.isEmpty()) {
102+
out.println(" super.afterRegistration(access);");
103+
}
95104
out.println(" return;");
96105
out.println(" }");
97106
}
98107
}
99108

100109
List<TypeMirror> keysFromAnnotation = getAnnotationValueList(singletonAnnotation, "value", TypeMirror.class);
110+
for (var superclass : singletonSuperclasses) {
111+
AnnotationMirror superclassAnnotation = getAnnotation(superclass, getType(ANNOTATION_CLASS_NAME));
112+
keysFromAnnotation.addAll(getAnnotationValueList(superclassAnnotation, "value", TypeMirror.class));
113+
}
114+
101115
if (keysFromAnnotation.isEmpty()) {
102116
String keyname = "" + annotatedType + ".class";
103117
out.println(" if (ImageSingletons.lookup(" + LAYERED_SINGLETON_INFO + ".class).handledDuringLoading(" + keyname + ")){");
@@ -130,6 +144,29 @@ private void processElement(TypeElement annotatedType) {
130144
}
131145
}
132146

147+
/**
148+
* Get the inheritance chain from {@code annotatedType} up to (excluding) the first
149+
* non-{@code @AutomaticallyRegisteredImageSingleton} type.
150+
*
151+
* @return a list ordered from the most specific to the least specific, empty if not even the
152+
* direct superclass is annotated
153+
*/
154+
private List<TypeElement> getSingletonSuperclasses(TypeElement annotatedType) {
155+
List<TypeElement> list = new ArrayList<>();
156+
for (TypeElement curr = annotatedType;;) {
157+
TypeMirror next = curr.getSuperclass();
158+
if (next.getKind() != TypeKind.DECLARED) {
159+
break;
160+
}
161+
curr = (TypeElement) ((DeclaredType) next).asElement();
162+
if (getAnnotation(curr, getType(ANNOTATION_CLASS_NAME)) == null) {
163+
break;
164+
}
165+
list.add(curr);
166+
}
167+
return list;
168+
}
169+
133170
/**
134171
* We allow inner classes to be annotated. To make the generated service name unique, we need to
135172
* concatenate the simple names of all outer classes.

0 commit comments

Comments
 (0)