diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java index d2f4a9830869..165b453ea75e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java @@ -35,20 +35,28 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import org.graalvm.nativeimage.c.function.CFunctionPointer; + +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner.OtherReason; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.BuildPhaseProvider; +import com.oracle.svm.core.classinitialization.ClassInitializationInfo; import com.oracle.svm.core.hub.AnnotatedSuperInfo; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.GenericInfo; +import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ExceptionSynthesizer; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.code.CompilationInfoSupport; import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -57,6 +65,7 @@ public class DynamicHubInitializer { + private final BigBang bb; private final SVMHost hostVM; private final AnalysisMetaAccess metaAccess; private final UnsupportedFeatures unsupportedFeatures; @@ -66,6 +75,7 @@ public class DynamicHubInitializer { private final Map annotatedInterfacesMap; private final Map interfacesEncodings; + private final Field dynamicHubClassInitializationInfoField; private final Field dynamicHubArrayHubField; private final Field dynamicHubEnclosingClassField; private final Field dynamicHubInterfacesEncodingField; @@ -74,16 +84,18 @@ public class DynamicHubInitializer { private final Field dynamicHubAnnotatedSuperInfoField; private final Field dynamicHubGenericInfoField; - public DynamicHubInitializer(AnalysisMetaAccess metaAccess, UnsupportedFeatures unsupportedFeatures, ConstantReflectionProvider constantReflection) { - this.metaAccess = metaAccess; - this.hostVM = (SVMHost) metaAccess.getUniverse().hostVM(); - this.unsupportedFeatures = unsupportedFeatures; - this.constantReflection = constantReflection; + public DynamicHubInitializer(BigBang bb) { + this.bb = bb; + this.metaAccess = bb.getMetaAccess(); + this.hostVM = (SVMHost) bb.getHostVM(); + this.unsupportedFeatures = bb.getUnsupportedFeatures(); + this.constantReflection = bb.getConstantReflectionProvider(); this.genericInterfacesMap = new ConcurrentHashMap<>(); this.annotatedInterfacesMap = new ConcurrentHashMap<>(); this.interfacesEncodings = new ConcurrentHashMap<>(); + dynamicHubClassInitializationInfoField = ReflectionUtil.lookupField(DynamicHub.class, "classInitializationInfo"); dynamicHubArrayHubField = ReflectionUtil.lookupField(DynamicHub.class, "arrayHub"); dynamicHubEnclosingClassField = ReflectionUtil.lookupField(DynamicHub.class, "enclosingClass"); dynamicHubInterfacesEncodingField = ReflectionUtil.lookupField(DynamicHub.class, "interfacesEncoding"); @@ -103,6 +115,9 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type) heapScanner.rescanObject(javaClass.getPackage()); DynamicHub hub = hostVM.dynamicHub(type); + if (hub.getClassInitializationInfo() == null) { + buildClassInitializationInfo(heapScanner, type, hub); + } if (hub.getGenericInfo() == null) { fillGenericInfo(heapScanner, type, hub); } @@ -205,6 +220,60 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type) heapScanner.rescanObject(hub, OtherReason.HUB); } + private void buildClassInitializationInfo(ImageHeapScanner heapScanner, AnalysisType type, DynamicHub hub) { + ClassInitializationInfo info; + if (hostVM.getClassInitializationSupport().shouldInitializeAtRuntime(type)) { + info = buildRuntimeInitializationInfo(type); + } else { + assert type.isInitialized(); + info = type.getClassInitializer() == null ? ClassInitializationInfo.NO_INITIALIZER_INFO_SINGLETON : ClassInitializationInfo.INITIALIZED_INFO_SINGLETON; + } + hub.setClassInitializationInfo(info); + heapScanner.rescanField(hub, dynamicHubClassInitializationInfoField); + } + + private ClassInitializationInfo buildRuntimeInitializationInfo(AnalysisType type) { + assert !type.isInitialized(); + try { + /* + * Check if there are any linking errors. This method throws an error even if linking + * already failed in a previous attempt. + */ + type.link(); + + } catch (VerifyError e) { + /* Synthesize a VerifyError to be thrown at run time. */ + AnalysisMethod throwVerifyError = metaAccess.lookupJavaMethod(ExceptionSynthesizer.throwExceptionMethod(VerifyError.class)); + registerAsCompiled(throwVerifyError); + return new ClassInitializationInfo(new MethodPointer(throwVerifyError)); + } catch (Throwable t) { + /* + * All other linking errors will be reported as NoClassDefFoundError when initialization + * is attempted at run time. + */ + return ClassInitializationInfo.FAILED_INFO_SINGLETON; + } + + /* + * Now we now that there are no linking errors, we can register the class initialization + * information. + */ + assert type.isLinked(); + CFunctionPointer classInitializerFunction = null; + AnalysisMethod classInitializer = type.getClassInitializer(); + if (classInitializer != null) { + assert classInitializer.getCode() != null; + registerAsCompiled(classInitializer); + classInitializerFunction = new MethodPointer(classInitializer); + } + return new ClassInitializationInfo(classInitializerFunction); + } + + private void registerAsCompiled(AnalysisMethod aMethod) { + bb.addRootMethod(aMethod).registerAsImplementationInvoked(); + CompilationInfoSupport.singleton().registerForcedCompilation(aMethod); + } + static class GenericInterfacesEncodingKey { final Type[] interfaces; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index 815197821ce0..71e15f336b8d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -59,7 +59,7 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer super(options, universe, providers, universe.hostVM(), executor, heartbeatCallback, unsupportedFeatures, SubstrateOptions.parseOnce()); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; - dynamicHubInitializer = new DynamicHubInitializer(metaAccess, unsupportedFeatures, providers.getConstantReflection()); + dynamicHubInitializer = new DynamicHubInitializer(this); unknownFieldHandler = new PointsToUnknownFieldHandler(this, metaAccess); callChecker = new CallChecker(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java index 42fead262f94..5e53c592131e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java @@ -43,7 +43,6 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.nativeimage.c.function.CFunctionPointer; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -61,11 +60,9 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.snippets.SnippetRuntime; import com.oracle.svm.core.util.UserError; -import com.oracle.svm.hosted.ExceptionSynthesizer; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.SVMHost; @@ -159,25 +156,13 @@ public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues o } @Override - public void duringAnalysis(DuringAnalysisAccess a) { - FeatureImpl.DuringAnalysisAccessImpl access = (FeatureImpl.DuringAnalysisAccessImpl) a; - + public void duringAnalysis(DuringAnalysisAccess access) { /* * Check early and often during static analysis if any class that must not have been * initialized during image building got initialized. We want to fail as early as possible, * even though we cannot pinpoint the exact time and reason why initialization happened. */ classInitializationSupport.checkDelayedInitialization(); - - for (AnalysisType type : access.getUniverse().getTypes()) { - if (type.isReachable()) { - DynamicHub hub = access.getHostVM().dynamicHub(type); - if (hub.getClassInitializationInfo() == null) { - buildClassInitializationInfo(access, type, hub); - access.requireAnalysisIteration(); - } - } - } } /** @@ -319,53 +304,4 @@ public void afterImageWrite(AfterImageWriteAccess a) { */ classInitializationSupport.checkDelayedInitialization(); } - - private void buildClassInitializationInfo(FeatureImpl.DuringAnalysisAccessImpl access, AnalysisType type, DynamicHub hub) { - ClassInitializationInfo info; - if (classInitializationSupport.shouldInitializeAtRuntime(type)) { - info = buildRuntimeInitializationInfo(access, type); - } else { - assert type.isInitialized(); - info = type.getClassInitializer() == null ? ClassInitializationInfo.NO_INITIALIZER_INFO_SINGLETON : ClassInitializationInfo.INITIALIZED_INFO_SINGLETON; - } - hub.setClassInitializationInfo(info); - universe.getHeapScanner().rescanField(hub, dynamicHubClassInitializationInfoField); - } - - private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImpl.DuringAnalysisAccessImpl access, AnalysisType type) { - assert !type.isInitialized(); - try { - /* - * Check if there are any linking errors. This method throws an error even if linking - * already failed in a previous attempt. - */ - type.link(); - - } catch (VerifyError e) { - /* Synthesize a VerifyError to be thrown at run time. */ - AnalysisMethod throwVerifyError = access.getMetaAccess().lookupJavaMethod(ExceptionSynthesizer.throwExceptionMethod(VerifyError.class)); - access.registerAsCompiled(throwVerifyError); - return new ClassInitializationInfo(new MethodPointer(throwVerifyError)); - } catch (Throwable t) { - /* - * All other linking errors will be reported as NoClassDefFoundError when initialization - * is attempted at run time. - */ - return ClassInitializationInfo.FAILED_INFO_SINGLETON; - } - - /* - * Now we now that there are no linking errors, we can register the class initialization - * information. - */ - assert type.isLinked(); - CFunctionPointer classInitializerFunction = null; - AnalysisMethod classInitializer = type.getClassInitializer(); - if (classInitializer != null) { - assert classInitializer.getCode() != null; - access.registerAsCompiled(classInitializer); - classInitializerFunction = new MethodPointer(classInitializer); - } - return new ClassInitializationInfo(classInitializerFunction); - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java index a5ec4b5b0fe8..7e854609e7f8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java @@ -35,6 +35,8 @@ import com.oracle.svm.core.jdk.NativeLibrarySupport; import com.oracle.svm.core.jni.JNIRuntimeAccess; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.c.NativeLibraries; @Platforms({InternalPlatform.PLATFORM_JNI.class}) @AutomaticFeature @@ -73,7 +75,10 @@ private static String getPlatformPreferencesClassName() { } private static void handlePreferencesClassReachable(@SuppressWarnings("unused") DuringAnalysisAccess access) { + NativeLibraries nativeLibraries = ((FeatureImpl.DuringAnalysisAccessImpl) access).getNativeLibraries(); + NativeLibrarySupport.singleton().preregisterUninitializedBuiltinLibrary("prefs"); + nativeLibraries.addStaticJniLibrary("prefs"); if (isDarwin()) { /* Darwin allocates a string array from native code */ JNIRuntimeAccess.register(String[].class); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrFeature.java index 6b5896910a6a..eec2a867b069 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrFeature.java @@ -28,7 +28,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; @@ -209,6 +208,12 @@ public void beforeAnalysis(Feature.BeforeAnalysisAccess access) { JfrManager manager = JfrManager.get(); runtime.addStartupHook(manager.startupHook()); runtime.addShutdownHook(manager.shutdownHook()); + + Class eventClass = access.findClassByName("jdk.internal.event.Event"); + if (eventClass != null) { + access.registerSubtypeReachabilityHandler(JfrFeature::eventSubtypeReachable, eventClass); + } + } @Override @@ -229,26 +234,21 @@ public void beforeCompilation(BeforeCompilationAccess a) { } } - @Override - public void duringAnalysis(DuringAnalysisAccess a) { + private static void eventSubtypeReachable(DuringAnalysisAccess a, Class c) { DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl) a; - Class eventClass = access.findClassByName("jdk.internal.event.Event"); - if (eventClass != null && access.isReachable(eventClass)) { - Set> s = access.reachableSubtypes(eventClass); - for (Class c : s) { - // Use canonical name for package private AbstractJDKEvent - if (c.getCanonicalName().equals("jdk.jfr.Event") || c.getCanonicalName().equals("jdk.internal.event.Event") || c.getCanonicalName().equals("jdk.jfr.events.AbstractJDKEvent") || - c.getCanonicalName().equals("jdk.jfr.events.AbstractBufferStatisticsEvent")) { - continue; - } - try { - Field f = c.getDeclaredField("eventHandler"); - RuntimeReflection.register(f); - access.rescanRoot(f); - } catch (Exception e) { - throw VMError.shouldNotReachHere("Unable to register eventHandler for: " + c.getCanonicalName(), e); - } - } + if (c.getCanonicalName().equals("jdk.jfr.Event") || + c.getCanonicalName().equals("jdk.internal.event.Event") || + c.getCanonicalName().equals("jdk.jfr.events.AbstractJDKEvent") || + c.getCanonicalName().equals("jdk.jfr.events.AbstractBufferStatisticsEvent")) { + return; + } + try { + Field f = c.getDeclaredField("eventHandler"); + RuntimeReflection.register(f); + access.rescanRoot(f); + a.requireAnalysisIteration(); + } catch (Exception e) { + throw VMError.shouldNotReachHere("Unable to register eventHandler for: " + c.getCanonicalName(), e); } } } diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java index 06cd1ffd3b15..76a494f4596a 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java @@ -289,7 +289,7 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) { if (!SubstitutionReflectivityFilter.shouldExclude(reflectMethod, access.getMetaAccess(), access.getUniverse())) { AnalysisMethod analysisMethod = access.getMetaAccess().lookupJavaMethod(reflectMethod); registerTypesForQueriedMethod(access, analysisMethod, reflectMethod); - registerHidingSubTypeMethods(analysisMethod, analysisMethod.getDeclaringClass()); + registerHidingSubTypeMethods(access, analysisMethod, analysisMethod.getDeclaringClass()); newQueriedMethods.add(reflectMethod); } } @@ -297,7 +297,7 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) { for (Executable method : reflectionMethods) { if (!SubstitutionReflectivityFilter.shouldExclude(method, access.getMetaAccess(), access.getUniverse())) { AnalysisMethod analysisMethod = access.getMetaAccess().lookupJavaMethod(method); - registerHidingSubTypeMethods(analysisMethod, analysisMethod.getDeclaringClass()); + registerHidingSubTypeMethods(access, analysisMethod, analysisMethod.getDeclaringClass()); } } } @@ -312,7 +312,7 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) { private final Map> seenHidingMethods = new HashMap<>(); - private void registerHidingSubTypeMethods(AnalysisMethod method, AnalysisType type) { + private void registerHidingSubTypeMethods(DuringAnalysisAccessImpl access, AnalysisMethod method, AnalysisType type) { if (!type.equals(method.getDeclaringClass()) && type.isReachable()) { if (!seenHidingMethods.containsKey(method) || !seenHidingMethods.get(method).contains(type)) { seenHidingMethods.computeIfAbsent(method, m -> new HashSet<>()).add(type); @@ -335,6 +335,12 @@ private void registerHidingSubTypeMethods(AnalysisMethod method, AnalysisType ty if (subClassMethod != null) { hidingMethods.add(subClassMethod); } + /* + * findMethod can lead to the creation of new AnalysisMethod, so we need to run + * another analysis iteration. + */ + access.requireAnalysisIteration(); + } catch (UnsupportedFeatureException | LinkageError e) { /* * A method that is not supposed to end up in the image is considered as being @@ -345,7 +351,7 @@ private void registerHidingSubTypeMethods(AnalysisMethod method, AnalysisType ty } for (AnalysisType subType : type.getSubTypes()) { if (!subType.equals(type)) { - registerHidingSubTypeMethods(method, subType); + registerHidingSubTypeMethods(access, method, subType); } } }