34
34
import com .oracle .svm .core .util .VMError ;
35
35
import com .oracle .svm .hosted .ImageClassLoader ;
36
36
37
- import jdk .internal .misc .Unsafe ;
38
37
import jdk .vm .ci .meta .MetaAccessProvider ;
39
38
40
39
class AllowAllHostedUsagesClassInitializationSupport extends ClassInitializationSupport {
@@ -43,23 +42,42 @@ class AllowAllHostedUsagesClassInitializationSupport extends ClassInitialization
43
42
super (metaAccess , loader );
44
43
}
45
44
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
+
46
65
@ Override
47
66
public void initializeAtRunTime (Class <?> clazz , String reason ) {
48
67
UserError .guarantee (!configurationSealed , "The class initialization configuration can be changed only before the phase analysis." );
49
68
classInitializationConfiguration .insert (clazz .getTypeName (), InitKind .RUN_TIME , reason , true );
50
- setSubclassesAsRunTime (clazz );
51
69
}
52
70
53
71
@ Override
54
72
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
+ }
57
76
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 );
63
81
}
64
82
65
83
@ Override
@@ -75,21 +93,6 @@ String reasonForClass(Class<?> clazz) {
75
93
}
76
94
}
77
95
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
-
93
96
@ Override
94
97
public void forceInitializeHosted (Class <?> clazz , String reason , boolean allowInitializationErrors ) {
95
98
if (clazz == null ) {
@@ -149,11 +152,6 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
149
152
return InitKind .BUILD_TIME ;
150
153
}
151
154
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
-
157
155
InitKind specifiedInitKind = specifiedInitKindFor (clazz );
158
156
InitKind clazzResult = specifiedInitKind != null ? specifiedInitKind : InitKind .RUN_TIME ;
159
157
@@ -175,18 +173,10 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
175
173
result = result .max (ensureClassInitialized (clazz , false ));
176
174
}
177
175
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
+ }
190
180
}
191
181
return result ;
192
182
}
0 commit comments