diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index d43a32bcd44d..bd4b60c6a5ef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -31,6 +31,7 @@ import static org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.registerInvocationPlugins; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.ref.Reference; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -1602,7 +1603,7 @@ private void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessP for (Method method : loader.findAnnotatedMethods(CConstant.class)) { if (LibCBase.isMethodProvidedInCurrentLibc(method)) { - classInitializationSupport.initializeAtBuildTime(method.getDeclaringClass(), "classes with " + CConstant.class.getSimpleName() + " annotations are always initialized"); + initializeAtBuildTime(method.getDeclaringClass(), classInitializationSupport, CConstant.class); nativeLibs.loadJavaMethod(metaAccess.lookupJavaMethod(method)); } } @@ -1613,38 +1614,38 @@ private void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessP } for (Class clazz : loader.findAnnotatedClasses(CStruct.class, false)) { if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) { - classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CStruct.class.getSimpleName() + " are always initialized"); + initializeAtBuildTime(clazz, classInitializationSupport, CStruct.class); nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz)); } } for (Class clazz : loader.findAnnotatedClasses(RawStructure.class, false)) { if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) { - classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + RawStructure.class.getSimpleName() + " are always initialized"); + initializeAtBuildTime(clazz, classInitializationSupport, RawStructure.class); nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz)); } } for (Class clazz : loader.findAnnotatedClasses(CPointerTo.class, false)) { if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) { - classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CPointerTo.class.getSimpleName() + " are always initialized"); + initializeAtBuildTime(clazz, classInitializationSupport, CPointerTo.class); nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz)); } } for (Class clazz : loader.findAnnotatedClasses(RawPointerTo.class, false)) { if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) { - classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + RawPointerTo.class.getSimpleName() + " are always initialized"); + initializeAtBuildTime(clazz, classInitializationSupport, RawPointerTo.class); nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz)); } } for (Class clazz : loader.findAnnotatedClasses(CEnum.class, false)) { if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) { ResolvedJavaType type = metaAccess.lookupJavaType(clazz); - classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CEnum.class.getSimpleName() + " are always initialized"); + initializeAtBuildTime(clazz, classInitializationSupport, CEnum.class); nativeLibs.loadJavaType(type); } } for (Class clazz : loader.findAnnotatedClasses(CContext.class, false)) { if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) { - classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CContext.class.getSimpleName() + " are always initialized"); + initializeAtBuildTime(clazz, classInitializationSupport, CContext.class); } } nativeLibs.processCLibraryAnnotations(loader); @@ -1653,6 +1654,12 @@ private void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessP nativeLibs.reportErrors(); } + private static void initializeAtBuildTime(Class clazz, ClassInitializationSupport classInitializationSupport, Class annotationForMessage) { + String message = "classes with " + annotationForMessage.getSimpleName() + " annotations are always initialized"; + classInitializationSupport.initializeAtBuildTime(clazz, message); + classInitializationSupport.forceInitializeHosted(clazz, message, false); + } + public AbstractImage getBuiltImage() { return image; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java index bff048b511b4..d5e8d79417a0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java @@ -34,7 +34,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; -import jdk.internal.misc.Unsafe; import jdk.vm.ci.meta.MetaAccessProvider; class AllowAllHostedUsagesClassInitializationSupport extends ClassInitializationSupport { @@ -43,23 +42,42 @@ class AllowAllHostedUsagesClassInitializationSupport extends ClassInitialization super(metaAccess, loader); } + @Override + public void initializeAtBuildTime(Class aClass, String reason) { + UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis."); + Class cur = aClass; + do { + classInitializationConfiguration.insert(cur.getTypeName(), InitKind.BUILD_TIME, cur == aClass ? reason : "super type of " + aClass.getTypeName(), true); + initializeInterfacesAtBuildTime(cur.getInterfaces(), "interface of " + aClass.getTypeName()); + cur = cur.getSuperclass(); + } while (cur != null); + } + + private void initializeInterfacesAtBuildTime(Class[] interfaces, String reason) { + for (Class iface : interfaces) { + if (metaAccess.lookupJavaType(iface).declaresDefaultMethods()) { + classInitializationConfiguration.insert(iface.getTypeName(), InitKind.BUILD_TIME, reason, true); + } + initializeInterfacesAtBuildTime(iface.getInterfaces(), reason); + } + } + @Override public void initializeAtRunTime(Class clazz, String reason) { UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis."); classInitializationConfiguration.insert(clazz.getTypeName(), InitKind.RUN_TIME, reason, true); - setSubclassesAsRunTime(clazz); } @Override public void rerunInitialization(Class clazz, String reason) { - UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis."); - classInitializationConfiguration.insert(clazz.getTypeName(), InitKind.RERUN, reason, true); + /* There is no more difference between RUN_TIME and RERUN. */ + initializeAtRunTime(clazz, reason); + } - try { - Unsafe.getUnsafe().ensureClassInitialized(clazz); - } catch (Throwable ex) { - throw UserError.abort(ex, "Class initialization failed for %s. The class is requested for re-running (reason: %s)", clazz.getTypeName(), reason); - } + @Override + public void rerunInitialization(String name, String reason) { + /* There is no more difference between RUN_TIME and RERUN. */ + initializeAtRunTime(name, reason); } @Override @@ -75,21 +93,6 @@ String reasonForClass(Class clazz) { } } - private void setSubclassesAsRunTime(Class clazz) { - if (clazz.isInterface() && !metaAccess.lookupJavaType(clazz).declaresDefaultMethods()) { - /* - * An interface that does not declare a default method is independent from a class - * initialization point of view, i.e., it is not initialized when a class implementing - * that interface is initialized. - */ - return; - } - loader.findSubclasses(clazz, false).stream() - .filter(c -> !c.equals(clazz)) - .filter(c -> !(c.isInterface() && !metaAccess.lookupJavaType(c).declaresDefaultMethods())) - .forEach(c -> classInitializationConfiguration.insert(c.getTypeName(), InitKind.RUN_TIME, "subtype of " + clazz.getTypeName(), true)); - } - @Override public void forceInitializeHosted(Class clazz, String reason, boolean allowInitializationErrors) { if (clazz == null) { @@ -149,11 +152,6 @@ InitKind computeInitKindAndMaybeInitializeClass(Class clazz, boolean memoize) return InitKind.BUILD_TIME; } - if (clazz.getTypeName().contains("$$StringConcat")) { - forceInitializeHosted(clazz, "string concatenation classes are initialized at build time", false); - return InitKind.BUILD_TIME; - } - InitKind specifiedInitKind = specifiedInitKindFor(clazz); InitKind clazzResult = specifiedInitKind != null ? specifiedInitKind : InitKind.RUN_TIME; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java index 853ad65a29da..60f3ca7ee9dd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java @@ -318,13 +318,6 @@ static String getTraceString(StackTraceElement[] trace) { return b.toString(); } - @Override - public void initializeAtBuildTime(Class aClass, String reason) { - UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis."); - classInitializationConfiguration.insert(aClass.getTypeName(), InitKind.BUILD_TIME, reason, true); - forceInitializeHosted(aClass, reason, false); - } - @Override public void reportClassInitialized(Class clazz, StackTraceElement[] stackTrace) { assert TraceClassInitialization.hasBeenSet(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java index 73f0151cae0d..d2e5e6f86948 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java @@ -188,6 +188,13 @@ public void rerunInitialization(Class clazz, String reason) { } } + @Override + public void initializeAtBuildTime(Class aClass, String reason) { + UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis."); + classInitializationConfiguration.insert(aClass.getTypeName(), InitKind.BUILD_TIME, reason, true); + forceInitializeHosted(aClass, reason, false); + } + private void setSubclassesAsRunTime(Class clazz) { if (clazz.isInterface() && !metaAccess.lookupJavaType(clazz).declaresDefaultMethods()) { /*