44
44
import java .util .function .Function ;
45
45
import java .util .stream .Collectors ;
46
46
47
- import jdk .graal .compiler .core .common .ContextClassLoaderScope ;
48
- import org .graalvm .nativeimage .libgraal .hosted .LibGraalLoader ;
49
47
import org .graalvm .collections .EconomicSet ;
50
48
import org .graalvm .nativeimage .ImageSingletons ;
51
49
import org .graalvm .nativeimage .impl .RuntimeClassInitializationSupport ;
52
50
import org .graalvm .nativeimage .impl .clinit .ClassInitializationTracking ;
51
+ import org .graalvm .nativeimage .libgraal .hosted .LibGraalLoader ;
53
52
53
+ import com .oracle .graal .pointsto .BigBang ;
54
54
import com .oracle .graal .pointsto .infrastructure .OriginalClassProvider ;
55
55
import com .oracle .graal .pointsto .meta .AnalysisType ;
56
56
import com .oracle .graal .pointsto .meta .BaseLayerType ;
57
57
import com .oracle .graal .pointsto .reports .ReportUtils ;
58
58
import com .oracle .svm .core .SubstrateOptions ;
59
+ import com .oracle .svm .core .imagelayer .ImageLayerBuildingSupport ;
59
60
import com .oracle .svm .core .option .AccumulatingLocatableMultiOptionValue ;
60
61
import com .oracle .svm .core .option .SubstrateOptionsParser ;
61
62
import com .oracle .svm .core .util .UserError ;
65
66
import com .oracle .svm .util .LogUtils ;
66
67
import com .oracle .svm .util .ModuleSupport ;
67
68
69
+ import jdk .graal .compiler .core .common .ContextClassLoaderScope ;
68
70
import jdk .graal .compiler .java .LambdaUtils ;
69
71
import jdk .internal .misc .Unsafe ;
70
72
import jdk .vm .ci .meta .MetaAccessProvider ;
73
75
/**
74
76
* The core class for deciding whether a class should be initialized during image building or class
75
77
* initialization should be delayed to runtime.
78
+ * <p>
79
+ * The initialization kind for all classes is encoded in the two registries:
80
+ * {@link #classInitializationConfiguration}, the user-configured initialization state, and
81
+ * {@link #classInitKinds}, the actual computed initialization state.
82
+ * <p>
83
+ * If for example the configured initialization kind, as registered in
84
+ * {@link #classInitializationConfiguration}, is {@link InitKind#BUILD_TIME} but invoking
85
+ * {@link #ensureClassInitialized(Class, boolean)} results in an error, e.g., a
86
+ * {@link NoClassDefFoundError}, then the actual initialization kind registered in
87
+ * {@link #classInitKinds} may be {@link InitKind#RUN_TIME} depending on the error resolution policy
88
+ * dictated by {@link LinkAtBuildTimeSupport#linkAtBuildTime(Class)}.
89
+ * <p>
90
+ * Classes with a simulated class initializer are neither registered as initialized at
91
+ * {@link InitKind#RUN_TIME} nor {@link InitKind#BUILD_TIME}. Instead
92
+ * {@link SimulateClassInitializerSupport} queries their initialization state to decide if
93
+ * simulation should be tried. If a class has a computed {@link InitKind#BUILD_TIME} initialization
94
+ * kind, i.e., its {@link AnalysisType#isInitialized()} returns true, simulation is skipped since
95
+ * the type is already considered as starting out as initialized at image run time (see
96
+ * {@link SimulateClassInitializerSupport#trySimulateClassInitializer(BigBang, AnalysisType)}). If a
97
+ * class was explicitly configured as {@link InitKind#RUN_TIME} initialized this will prevent it
98
+ * from being simulated.
99
+ * <p>
100
+ * There are some similarities and differences between simulated and build-time initialized classes.
101
+ * At image execution time they both start out as initialized: there are no run-time class
102
+ * initialization checks and the class initializer itself is not even present, it was not AOT
103
+ * compiled. However, for a simulated class its initialization status in the hosting VM that runs
104
+ * the image generator does not matter; it may or may not have been initialized. Whereas, a
105
+ * build-time initialized class is by definition initialized in the hosting VM. Consequently, the
106
+ * static fields of a simulated class reference image heap values computed by the class initializer
107
+ * simulation, but they do not correspond to hosted objects. In contrast, static fields of a
108
+ * build-time initialized class reference image heap values that were copied from the corresponding
109
+ * fields in the hosting VM.
76
110
*/
77
111
public class ClassInitializationSupport implements RuntimeClassInitializationSupport {
78
112
@@ -125,7 +159,29 @@ public ClassInitializationSupport(MetaAccessProvider metaAccess, ImageClassLoade
125
159
this .loader = loader ;
126
160
}
127
161
128
- public void setConfigurationSealed (boolean sealed ) {
162
+ /**
163
+ * Seal the configuration, blocking if another thread is trying to seal the configuration or an
164
+ * unsealed-configuration window is currently open in another thread.
165
+ */
166
+ public synchronized void sealConfiguration () {
167
+ setConfigurationSealed (true );
168
+ }
169
+
170
+ /**
171
+ * Run the action in an unsealed-configuration window, blocking if another thread is trying to
172
+ * seal the configuration or an unsealed-configuration window is currently open in another
173
+ * thread. The window is reentrant, i.e., it will not block the thread that opened the window
174
+ * from trying to reenter the window. Note that if the configuration was not sealed when the
175
+ * window was opened this will not affect the seal status.
176
+ */
177
+ public synchronized void withUnsealedConfiguration (Runnable action ) {
178
+ var previouslySealed = configurationSealed ;
179
+ setConfigurationSealed (false );
180
+ action .run ();
181
+ setConfigurationSealed (previouslySealed );
182
+ }
183
+
184
+ private void setConfigurationSealed (boolean sealed ) {
129
185
configurationSealed = sealed ;
130
186
if (configurationSealed && ClassInitializationOptions .PrintClassInitialization .getValue ()) {
131
187
List <ClassOrPackageConfig > allConfigs = classInitializationConfiguration .allConfigs ();
@@ -170,7 +226,7 @@ Set<Class<?>> classesWithKind(InitKind kind) {
170
226
*/
171
227
public boolean maybeInitializeAtBuildTime (ResolvedJavaType type ) {
172
228
if (type instanceof AnalysisType analysisType && analysisType .getWrapped () instanceof BaseLayerType baseLayerType ) {
173
- return baseLayerType .initializedAtBuildTime ();
229
+ return baseLayerType .isInitialized ();
174
230
}
175
231
return maybeInitializeAtBuildTime (OriginalClassProvider .getJavaClass (type ));
176
232
}
@@ -350,8 +406,26 @@ public void forceInitializeHosted(Class<?> clazz, String reason, boolean allowIn
350
406
if (clazz == null ) {
351
407
return ;
352
408
}
409
+
353
410
classInitializationConfiguration .insert (clazz .getTypeName (), InitKind .BUILD_TIME , reason , true );
354
411
InitKind initKind = ensureClassInitialized (clazz , allowInitializationErrors );
412
+ if (initKind == InitKind .RUN_TIME ) {
413
+ assert allowInitializationErrors || !LinkAtBuildTimeSupport .singleton ().linkAtBuildTime (clazz );
414
+ if (ImageLayerBuildingSupport .buildingApplicationLayer ()) {
415
+ /*
416
+ * Special case for application layer building. If a base layer class was configured
417
+ * with --initialize-at-build-time but its initialization failed, then the computed
418
+ * init kind will be RUN_TIME, different from its configured init kind of
419
+ * BUILD_TIME. In the app layer the computed init kind from the previous layer is
420
+ * registered as the configured init kind, but if the --initialize-at-build-time was
421
+ * already processed for the class then it will already have a conflicting
422
+ * configured init kind of BUILD_TIME. Update the configuration registry to allow
423
+ * the RUN_TIME registration coming from the base layer. (GR-65405)
424
+ */
425
+ classInitializationConfiguration .updateStrict (clazz .getTypeName (), InitKind .BUILD_TIME , InitKind .RUN_TIME ,
426
+ "Allow the registration of the computed run time initialization kind from a previous layer for classes whose build time initialization fails." );
427
+ }
428
+ }
355
429
classInitKinds .put (clazz , initKind );
356
430
357
431
forceInitializeHosted (clazz .getSuperclass (), "super type of " + clazz .getTypeName (), allowInitializationErrors );
@@ -369,7 +443,8 @@ private void forceInitializeInterfaces(Class<?>[] interfaces, String reason) {
369
443
if (metaAccess .lookupJavaType (iface ).declaresDefaultMethods ()) {
370
444
classInitializationConfiguration .insert (iface .getTypeName (), InitKind .BUILD_TIME , reason , true );
371
445
372
- ensureClassInitialized (iface , false );
446
+ InitKind initKind = ensureClassInitialized (iface , false );
447
+ VMError .guarantee (initKind == InitKind .BUILD_TIME , "Initialization of %s failed so all interfaces with default methods must be already initialized." , iface .getTypeName ());
373
448
classInitKinds .put (iface , InitKind .BUILD_TIME );
374
449
}
375
450
forceInitializeInterfaces (iface .getInterfaces (), "super type of " + iface .getTypeName ());
0 commit comments