3434import com .oracle .svm .core .util .VMError ;
3535import com .oracle .svm .hosted .ImageClassLoader ;
3636
37- import jdk .internal .misc .Unsafe ;
3837import jdk .vm .ci .meta .MetaAccessProvider ;
3938
4039class AllowAllHostedUsagesClassInitializationSupport extends ClassInitializationSupport {
@@ -43,23 +42,42 @@ class AllowAllHostedUsagesClassInitializationSupport extends ClassInitialization
4342 super (metaAccess , loader );
4443 }
4544
45+ @ Override
46+ public void initializeAtBuildTime (Class <?> aClass , String reason ) {
47+ UserError .guarantee (!configurationSealed , "The class initialization configuration can be changed only before the phase analysis." );
48+ Class <?> cur = aClass ;
49+ do {
50+ classInitializationConfiguration .insert (cur .getTypeName (), InitKind .BUILD_TIME , cur == aClass ? reason : "super type of " + aClass .getTypeName (), true );
51+ initializeInterfacesAtBuildTime (cur .getInterfaces (), "interface of " + aClass .getTypeName ());
52+ cur = cur .getSuperclass ();
53+ } while (cur != null );
54+ }
55+
56+ private void initializeInterfacesAtBuildTime (Class <?>[] interfaces , String reason ) {
57+ for (Class <?> iface : interfaces ) {
58+ if (metaAccess .lookupJavaType (iface ).declaresDefaultMethods ()) {
59+ classInitializationConfiguration .insert (iface .getTypeName (), InitKind .BUILD_TIME , reason , true );
60+ }
61+ initializeInterfacesAtBuildTime (iface .getInterfaces (), reason );
62+ }
63+ }
64+
4665 @ Override
4766 public void initializeAtRunTime (Class <?> clazz , String reason ) {
4867 UserError .guarantee (!configurationSealed , "The class initialization configuration can be changed only before the phase analysis." );
4968 classInitializationConfiguration .insert (clazz .getTypeName (), InitKind .RUN_TIME , reason , true );
50- setSubclassesAsRunTime (clazz );
5169 }
5270
5371 @ Override
5472 public void rerunInitialization (Class <?> clazz , String reason ) {
55- UserError .guarantee (!configurationSealed , "The class initialization configuration can be changed only before the phase analysis." );
56- classInitializationConfiguration .insert (clazz .getTypeName (), InitKind .RERUN , reason , true );
73+ /* There is no more difference between RUN_TIME and RERUN. */
74+ initializeAtRunTime (clazz , reason );
75+ }
5776
58- try {
59- Unsafe .getUnsafe ().ensureClassInitialized (clazz );
60- } catch (Throwable ex ) {
61- throw UserError .abort (ex , "Class initialization failed for %s. The class is requested for re-running (reason: %s)" , clazz .getTypeName (), reason );
62- }
77+ @ Override
78+ public void rerunInitialization (String name , String reason ) {
79+ /* There is no more difference between RUN_TIME and RERUN. */
80+ initializeAtRunTime (name , reason );
6381 }
6482
6583 @ Override
@@ -75,21 +93,6 @@ String reasonForClass(Class<?> clazz) {
7593 }
7694 }
7795
78- private void setSubclassesAsRunTime (Class <?> clazz ) {
79- if (clazz .isInterface () && !metaAccess .lookupJavaType (clazz ).declaresDefaultMethods ()) {
80- /*
81- * An interface that does not declare a default method is independent from a class
82- * initialization point of view, i.e., it is not initialized when a class implementing
83- * that interface is initialized.
84- */
85- return ;
86- }
87- loader .findSubclasses (clazz , false ).stream ()
88- .filter (c -> !c .equals (clazz ))
89- .filter (c -> !(c .isInterface () && !metaAccess .lookupJavaType (c ).declaresDefaultMethods ()))
90- .forEach (c -> classInitializationConfiguration .insert (c .getTypeName (), InitKind .RUN_TIME , "subtype of " + clazz .getTypeName (), true ));
91- }
92-
9396 @ Override
9497 public void forceInitializeHosted (Class <?> clazz , String reason , boolean allowInitializationErrors ) {
9598 if (clazz == null ) {
@@ -149,11 +152,6 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
149152 return InitKind .BUILD_TIME ;
150153 }
151154
152- if (clazz .getTypeName ().contains ("$$StringConcat" )) {
153- forceInitializeHosted (clazz , "string concatenation classes are initialized at build time" , false );
154- return InitKind .BUILD_TIME ;
155- }
156-
157155 InitKind specifiedInitKind = specifiedInitKindFor (clazz );
158156 InitKind clazzResult = specifiedInitKind != null ? specifiedInitKind : InitKind .RUN_TIME ;
159157
@@ -175,18 +173,10 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
175173 result = result .max (ensureClassInitialized (clazz , false ));
176174 }
177175
178- /*
179- * Unfortunately, the computation of canInitializeWithoutSideEffects is not completely
180- * deterministic: Consider a class A whose class initializer depends on class B. Assume
181- * class B has no other dependencies and can therefore be initialized at build time.
182- * When class A is analyzed after class B has been initialized, it can also be
183- * initialized at build time. But when class A is analyzed before class B has been
184- * initialized, it cannot. Since two threads can analyze class A at the same time (there
185- * is no per-class locking) and another thread can initialize B at the same time, we can
186- * have a conflicting initialization status. In that case, BUILD_TIME must win over
187- * RUN_TIME because one thread has already initialized class A.
188- */
189- result = classInitKinds .merge (clazz , result , InitKind ::min );
176+ InitKind previous = classInitKinds .putIfAbsent (clazz , result );
177+ if (previous != null && previous != result ) {
178+ throw VMError .shouldNotReachHere ("Conflicting class initialization kind: " + previous + " != " + result + " for " + clazz );
179+ }
190180 }
191181 return result ;
192182 }
0 commit comments