Skip to content

Commit c7af7b7

Browse files
author
Christian Wimmer
committed
[GR-36817] Build class initialization information eagerly when a type gets reachable.
PullRequest: graal/10989
2 parents 384db57 + b4dcb63 commit c7af7b7

File tree

6 files changed

+111
-95
lines changed

6 files changed

+111
-95
lines changed

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

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,28 @@
3535
import java.util.Optional;
3636
import java.util.concurrent.ConcurrentHashMap;
3737

38+
import org.graalvm.nativeimage.c.function.CFunctionPointer;
39+
40+
import com.oracle.graal.pointsto.BigBang;
3841
import com.oracle.graal.pointsto.ObjectScanner.OtherReason;
3942
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
4043
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
4144
import com.oracle.graal.pointsto.heap.ImageHeapScanner;
4245
import com.oracle.graal.pointsto.meta.AnalysisField;
4346
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
47+
import com.oracle.graal.pointsto.meta.AnalysisMethod;
4448
import com.oracle.graal.pointsto.meta.AnalysisType;
4549
import com.oracle.svm.core.BuildPhaseProvider;
50+
import com.oracle.svm.core.classinitialization.ClassInitializationInfo;
4651
import com.oracle.svm.core.hub.AnnotatedSuperInfo;
4752
import com.oracle.svm.core.hub.DynamicHub;
4853
import com.oracle.svm.core.hub.GenericInfo;
54+
import com.oracle.svm.core.meta.MethodPointer;
4955
import com.oracle.svm.core.meta.SubstrateObjectConstant;
5056
import com.oracle.svm.core.util.VMError;
57+
import com.oracle.svm.hosted.ExceptionSynthesizer;
5158
import com.oracle.svm.hosted.SVMHost;
59+
import com.oracle.svm.hosted.code.CompilationInfoSupport;
5260
import com.oracle.svm.util.ReflectionUtil;
5361

5462
import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -57,6 +65,7 @@
5765

5866
public class DynamicHubInitializer {
5967

68+
private final BigBang bb;
6069
private final SVMHost hostVM;
6170
private final AnalysisMetaAccess metaAccess;
6271
private final UnsupportedFeatures unsupportedFeatures;
@@ -66,6 +75,7 @@ public class DynamicHubInitializer {
6675
private final Map<AnnotatedInterfacesEncodingKey, AnnotatedType[]> annotatedInterfacesMap;
6776
private final Map<InterfacesEncodingKey, DynamicHub[]> interfacesEncodings;
6877

78+
private final Field dynamicHubClassInitializationInfoField;
6979
private final Field dynamicHubArrayHubField;
7080
private final Field dynamicHubEnclosingClassField;
7181
private final Field dynamicHubInterfacesEncodingField;
@@ -74,16 +84,18 @@ public class DynamicHubInitializer {
7484
private final Field dynamicHubAnnotatedSuperInfoField;
7585
private final Field dynamicHubGenericInfoField;
7686

77-
public DynamicHubInitializer(AnalysisMetaAccess metaAccess, UnsupportedFeatures unsupportedFeatures, ConstantReflectionProvider constantReflection) {
78-
this.metaAccess = metaAccess;
79-
this.hostVM = (SVMHost) metaAccess.getUniverse().hostVM();
80-
this.unsupportedFeatures = unsupportedFeatures;
81-
this.constantReflection = constantReflection;
87+
public DynamicHubInitializer(BigBang bb) {
88+
this.bb = bb;
89+
this.metaAccess = bb.getMetaAccess();
90+
this.hostVM = (SVMHost) bb.getHostVM();
91+
this.unsupportedFeatures = bb.getUnsupportedFeatures();
92+
this.constantReflection = bb.getConstantReflectionProvider();
8293

8394
this.genericInterfacesMap = new ConcurrentHashMap<>();
8495
this.annotatedInterfacesMap = new ConcurrentHashMap<>();
8596
this.interfacesEncodings = new ConcurrentHashMap<>();
8697

98+
dynamicHubClassInitializationInfoField = ReflectionUtil.lookupField(DynamicHub.class, "classInitializationInfo");
8799
dynamicHubArrayHubField = ReflectionUtil.lookupField(DynamicHub.class, "arrayHub");
88100
dynamicHubEnclosingClassField = ReflectionUtil.lookupField(DynamicHub.class, "enclosingClass");
89101
dynamicHubInterfacesEncodingField = ReflectionUtil.lookupField(DynamicHub.class, "interfacesEncoding");
@@ -103,6 +115,9 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type)
103115
heapScanner.rescanObject(javaClass.getPackage());
104116

105117
DynamicHub hub = hostVM.dynamicHub(type);
118+
if (hub.getClassInitializationInfo() == null) {
119+
buildClassInitializationInfo(heapScanner, type, hub);
120+
}
106121
if (hub.getGenericInfo() == null) {
107122
fillGenericInfo(heapScanner, type, hub);
108123
}
@@ -205,6 +220,60 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type)
205220
heapScanner.rescanObject(hub, OtherReason.HUB);
206221
}
207222

223+
private void buildClassInitializationInfo(ImageHeapScanner heapScanner, AnalysisType type, DynamicHub hub) {
224+
ClassInitializationInfo info;
225+
if (hostVM.getClassInitializationSupport().shouldInitializeAtRuntime(type)) {
226+
info = buildRuntimeInitializationInfo(type);
227+
} else {
228+
assert type.isInitialized();
229+
info = type.getClassInitializer() == null ? ClassInitializationInfo.NO_INITIALIZER_INFO_SINGLETON : ClassInitializationInfo.INITIALIZED_INFO_SINGLETON;
230+
}
231+
hub.setClassInitializationInfo(info);
232+
heapScanner.rescanField(hub, dynamicHubClassInitializationInfoField);
233+
}
234+
235+
private ClassInitializationInfo buildRuntimeInitializationInfo(AnalysisType type) {
236+
assert !type.isInitialized();
237+
try {
238+
/*
239+
* Check if there are any linking errors. This method throws an error even if linking
240+
* already failed in a previous attempt.
241+
*/
242+
type.link();
243+
244+
} catch (VerifyError e) {
245+
/* Synthesize a VerifyError to be thrown at run time. */
246+
AnalysisMethod throwVerifyError = metaAccess.lookupJavaMethod(ExceptionSynthesizer.throwExceptionMethod(VerifyError.class));
247+
registerAsCompiled(throwVerifyError);
248+
return new ClassInitializationInfo(new MethodPointer(throwVerifyError));
249+
} catch (Throwable t) {
250+
/*
251+
* All other linking errors will be reported as NoClassDefFoundError when initialization
252+
* is attempted at run time.
253+
*/
254+
return ClassInitializationInfo.FAILED_INFO_SINGLETON;
255+
}
256+
257+
/*
258+
* Now we now that there are no linking errors, we can register the class initialization
259+
* information.
260+
*/
261+
assert type.isLinked();
262+
CFunctionPointer classInitializerFunction = null;
263+
AnalysisMethod classInitializer = type.getClassInitializer();
264+
if (classInitializer != null) {
265+
assert classInitializer.getCode() != null;
266+
registerAsCompiled(classInitializer);
267+
classInitializerFunction = new MethodPointer(classInitializer);
268+
}
269+
return new ClassInitializationInfo(classInitializerFunction);
270+
}
271+
272+
private void registerAsCompiled(AnalysisMethod aMethod) {
273+
bb.addRootMethod(aMethod).registerAsImplementationInvoked();
274+
CompilationInfoSupport.singleton().registerForcedCompilation(aMethod);
275+
}
276+
208277
static class GenericInterfacesEncodingKey {
209278
final Type[] interfaces;
210279

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer
5959
super(options, universe, providers, universe.hostVM(), executor, heartbeatCallback, unsupportedFeatures, SubstrateOptions.parseOnce());
6060
this.annotationSubstitutionProcessor = annotationSubstitutionProcessor;
6161

62-
dynamicHubInitializer = new DynamicHubInitializer(metaAccess, unsupportedFeatures, providers.getConstantReflection());
62+
dynamicHubInitializer = new DynamicHubInitializer(this);
6363
unknownFieldHandler = new PointsToUnknownFieldHandler(this, metaAccess);
6464
callChecker = new CallChecker();
6565
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import org.graalvm.compiler.graph.Node;
4444
import org.graalvm.compiler.options.OptionValues;
4545
import org.graalvm.compiler.phases.util.Providers;
46-
import org.graalvm.nativeimage.c.function.CFunctionPointer;
4746

4847
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
4948
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
@@ -61,11 +60,9 @@
6160
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
6261
import com.oracle.svm.core.graal.snippets.NodeLoweringProvider;
6362
import com.oracle.svm.core.hub.DynamicHub;
64-
import com.oracle.svm.core.meta.MethodPointer;
6563
import com.oracle.svm.core.option.SubstrateOptionsParser;
6664
import com.oracle.svm.core.snippets.SnippetRuntime;
6765
import com.oracle.svm.core.util.UserError;
68-
import com.oracle.svm.hosted.ExceptionSynthesizer;
6966
import com.oracle.svm.hosted.FeatureImpl;
7067
import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl;
7168
import com.oracle.svm.hosted.SVMHost;
@@ -159,25 +156,13 @@ public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues o
159156
}
160157

161158
@Override
162-
public void duringAnalysis(DuringAnalysisAccess a) {
163-
FeatureImpl.DuringAnalysisAccessImpl access = (FeatureImpl.DuringAnalysisAccessImpl) a;
164-
159+
public void duringAnalysis(DuringAnalysisAccess access) {
165160
/*
166161
* Check early and often during static analysis if any class that must not have been
167162
* initialized during image building got initialized. We want to fail as early as possible,
168163
* even though we cannot pinpoint the exact time and reason why initialization happened.
169164
*/
170165
classInitializationSupport.checkDelayedInitialization();
171-
172-
for (AnalysisType type : access.getUniverse().getTypes()) {
173-
if (type.isReachable()) {
174-
DynamicHub hub = access.getHostVM().dynamicHub(type);
175-
if (hub.getClassInitializationInfo() == null) {
176-
buildClassInitializationInfo(access, type, hub);
177-
access.requireAnalysisIteration();
178-
}
179-
}
180-
}
181166
}
182167

183168
/**
@@ -319,53 +304,4 @@ public void afterImageWrite(AfterImageWriteAccess a) {
319304
*/
320305
classInitializationSupport.checkDelayedInitialization();
321306
}
322-
323-
private void buildClassInitializationInfo(FeatureImpl.DuringAnalysisAccessImpl access, AnalysisType type, DynamicHub hub) {
324-
ClassInitializationInfo info;
325-
if (classInitializationSupport.shouldInitializeAtRuntime(type)) {
326-
info = buildRuntimeInitializationInfo(access, type);
327-
} else {
328-
assert type.isInitialized();
329-
info = type.getClassInitializer() == null ? ClassInitializationInfo.NO_INITIALIZER_INFO_SINGLETON : ClassInitializationInfo.INITIALIZED_INFO_SINGLETON;
330-
}
331-
hub.setClassInitializationInfo(info);
332-
universe.getHeapScanner().rescanField(hub, dynamicHubClassInitializationInfoField);
333-
}
334-
335-
private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImpl.DuringAnalysisAccessImpl access, AnalysisType type) {
336-
assert !type.isInitialized();
337-
try {
338-
/*
339-
* Check if there are any linking errors. This method throws an error even if linking
340-
* already failed in a previous attempt.
341-
*/
342-
type.link();
343-
344-
} catch (VerifyError e) {
345-
/* Synthesize a VerifyError to be thrown at run time. */
346-
AnalysisMethod throwVerifyError = access.getMetaAccess().lookupJavaMethod(ExceptionSynthesizer.throwExceptionMethod(VerifyError.class));
347-
access.registerAsCompiled(throwVerifyError);
348-
return new ClassInitializationInfo(new MethodPointer(throwVerifyError));
349-
} catch (Throwable t) {
350-
/*
351-
* All other linking errors will be reported as NoClassDefFoundError when initialization
352-
* is attempted at run time.
353-
*/
354-
return ClassInitializationInfo.FAILED_INFO_SINGLETON;
355-
}
356-
357-
/*
358-
* Now we now that there are no linking errors, we can register the class initialization
359-
* information.
360-
*/
361-
assert type.isLinked();
362-
CFunctionPointer classInitializerFunction = null;
363-
AnalysisMethod classInitializer = type.getClassInitializer();
364-
if (classInitializer != null) {
365-
assert classInitializer.getCode() != null;
366-
access.registerAsCompiled(classInitializer);
367-
classInitializerFunction = new MethodPointer(classInitializer);
368-
}
369-
return new ClassInitializationInfo(classInitializerFunction);
370-
}
371307
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import com.oracle.svm.core.jdk.NativeLibrarySupport;
3636
import com.oracle.svm.core.jni.JNIRuntimeAccess;
3737
import com.oracle.svm.core.util.VMError;
38+
import com.oracle.svm.hosted.FeatureImpl;
39+
import com.oracle.svm.hosted.c.NativeLibraries;
3840

3941
@Platforms({InternalPlatform.PLATFORM_JNI.class})
4042
@AutomaticFeature
@@ -73,7 +75,10 @@ private static String getPlatformPreferencesClassName() {
7375
}
7476

7577
private static void handlePreferencesClassReachable(@SuppressWarnings("unused") DuringAnalysisAccess access) {
78+
NativeLibraries nativeLibraries = ((FeatureImpl.DuringAnalysisAccessImpl) access).getNativeLibraries();
79+
7680
NativeLibrarySupport.singleton().preregisterUninitializedBuiltinLibrary("prefs");
81+
nativeLibraries.addStaticJniLibrary("prefs");
7782
if (isDarwin()) {
7883
/* Darwin allocates a string array from native code */
7984
JNIRuntimeAccess.register(String[].class);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrFeature.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.util.Collection;
2929
import java.util.Collections;
3030
import java.util.List;
31-
import java.util.Set;
3231

3332
import org.graalvm.nativeimage.ImageSingletons;
3433
import org.graalvm.nativeimage.hosted.Feature;
@@ -209,6 +208,12 @@ public void beforeAnalysis(Feature.BeforeAnalysisAccess access) {
209208
JfrManager manager = JfrManager.get();
210209
runtime.addStartupHook(manager.startupHook());
211210
runtime.addShutdownHook(manager.shutdownHook());
211+
212+
Class<?> eventClass = access.findClassByName("jdk.internal.event.Event");
213+
if (eventClass != null) {
214+
access.registerSubtypeReachabilityHandler(JfrFeature::eventSubtypeReachable, eventClass);
215+
}
216+
212217
}
213218

214219
@Override
@@ -229,26 +234,21 @@ public void beforeCompilation(BeforeCompilationAccess a) {
229234
}
230235
}
231236

232-
@Override
233-
public void duringAnalysis(DuringAnalysisAccess a) {
237+
private static void eventSubtypeReachable(DuringAnalysisAccess a, Class<?> c) {
234238
DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl) a;
235-
Class<?> eventClass = access.findClassByName("jdk.internal.event.Event");
236-
if (eventClass != null && access.isReachable(eventClass)) {
237-
Set<Class<?>> s = access.reachableSubtypes(eventClass);
238-
for (Class<?> c : s) {
239-
// Use canonical name for package private AbstractJDKEvent
240-
if (c.getCanonicalName().equals("jdk.jfr.Event") || c.getCanonicalName().equals("jdk.internal.event.Event") || c.getCanonicalName().equals("jdk.jfr.events.AbstractJDKEvent") ||
241-
c.getCanonicalName().equals("jdk.jfr.events.AbstractBufferStatisticsEvent")) {
242-
continue;
243-
}
244-
try {
245-
Field f = c.getDeclaredField("eventHandler");
246-
RuntimeReflection.register(f);
247-
access.rescanRoot(f);
248-
} catch (Exception e) {
249-
throw VMError.shouldNotReachHere("Unable to register eventHandler for: " + c.getCanonicalName(), e);
250-
}
251-
}
239+
if (c.getCanonicalName().equals("jdk.jfr.Event") ||
240+
c.getCanonicalName().equals("jdk.internal.event.Event") ||
241+
c.getCanonicalName().equals("jdk.jfr.events.AbstractJDKEvent") ||
242+
c.getCanonicalName().equals("jdk.jfr.events.AbstractBufferStatisticsEvent")) {
243+
return;
244+
}
245+
try {
246+
Field f = c.getDeclaredField("eventHandler");
247+
RuntimeReflection.register(f);
248+
access.rescanRoot(f);
249+
a.requireAnalysisIteration();
250+
} catch (Exception e) {
251+
throw VMError.shouldNotReachHere("Unable to register eventHandler for: " + c.getCanonicalName(), e);
252252
}
253253
}
254254
}

substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,15 +289,15 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) {
289289
if (!SubstitutionReflectivityFilter.shouldExclude(reflectMethod, access.getMetaAccess(), access.getUniverse())) {
290290
AnalysisMethod analysisMethod = access.getMetaAccess().lookupJavaMethod(reflectMethod);
291291
registerTypesForQueriedMethod(access, analysisMethod, reflectMethod);
292-
registerHidingSubTypeMethods(analysisMethod, analysisMethod.getDeclaringClass());
292+
registerHidingSubTypeMethods(access, analysisMethod, analysisMethod.getDeclaringClass());
293293
newQueriedMethods.add(reflectMethod);
294294
}
295295
}
296296
queriedMethods = newQueriedMethods;
297297
for (Executable method : reflectionMethods) {
298298
if (!SubstitutionReflectivityFilter.shouldExclude(method, access.getMetaAccess(), access.getUniverse())) {
299299
AnalysisMethod analysisMethod = access.getMetaAccess().lookupJavaMethod(method);
300-
registerHidingSubTypeMethods(analysisMethod, analysisMethod.getDeclaringClass());
300+
registerHidingSubTypeMethods(access, analysisMethod, analysisMethod.getDeclaringClass());
301301
}
302302
}
303303
}
@@ -312,7 +312,7 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) {
312312

313313
private final Map<AnalysisMethod, Set<AnalysisType>> seenHidingMethods = new HashMap<>();
314314

315-
private void registerHidingSubTypeMethods(AnalysisMethod method, AnalysisType type) {
315+
private void registerHidingSubTypeMethods(DuringAnalysisAccessImpl access, AnalysisMethod method, AnalysisType type) {
316316
if (!type.equals(method.getDeclaringClass()) && type.isReachable()) {
317317
if (!seenHidingMethods.containsKey(method) || !seenHidingMethods.get(method).contains(type)) {
318318
seenHidingMethods.computeIfAbsent(method, m -> new HashSet<>()).add(type);
@@ -335,6 +335,12 @@ private void registerHidingSubTypeMethods(AnalysisMethod method, AnalysisType ty
335335
if (subClassMethod != null) {
336336
hidingMethods.add(subClassMethod);
337337
}
338+
/*
339+
* findMethod can lead to the creation of new AnalysisMethod, so we need to run
340+
* another analysis iteration.
341+
*/
342+
access.requireAnalysisIteration();
343+
338344
} catch (UnsupportedFeatureException | LinkageError e) {
339345
/*
340346
* 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
345351
}
346352
for (AnalysisType subType : type.getSubTypes()) {
347353
if (!subType.equals(type)) {
348-
registerHidingSubTypeMethods(method, subType);
354+
registerHidingSubTypeMethods(access, method, subType);
349355
}
350356
}
351357
}

0 commit comments

Comments
 (0)