Skip to content

Commit d603e08

Browse files
committed
svm: also look for run-time initialized super interfaces before considering Proxies as build-time initialized
1 parent 3f38173 commit d603e08

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import java.util.stream.Collectors;
3838
import java.util.stream.Stream;
3939

40+
import org.graalvm.collections.EconomicSet;
41+
import org.graalvm.compiler.debug.GraalError;
4042
import org.graalvm.compiler.java.LambdaUtils;
4143

4244
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
@@ -329,7 +331,7 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize,
329331
superResult = superResult.max(processInterfaces(clazz, memoize, earlyClassInitializerAnalyzedClasses));
330332

331333
if (superResult == InitKind.BUILD_TIME && (Proxy.isProxyClass(clazz) || LambdaUtils.isLambdaType(metaAccess.lookupJavaType(clazz)))) {
332-
if (!Proxy.isProxyClass(clazz) || areAllInterfaceMethodsSafeToInitializeAtBuildTime(clazz)) {
334+
if (!Proxy.isProxyClass(clazz) || !implementsRunTimeInitializedInterface(clazz)) {
333335
forceInitializeHosted(clazz, "proxy/lambda classes with interfaces initialized at build time are also initialized at build time", false);
334336
return InitKind.BUILD_TIME;
335337
}
@@ -377,14 +379,29 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize,
377379
}
378380

379381
/**
380-
* Interfaces are only safe to initialize at build time if no interface method references a type
381-
* that {@linkplain #shouldInitializeAtRuntime should be initialized at run time}.
382+
* Interfaces must be initialized at run time if any interface method references a type that
383+
* {@linkplain #shouldInitializeAtRuntime should be initialized at run time}.
382384
*/
383-
private boolean areAllInterfaceMethodsSafeToInitializeAtBuildTime(Class<?> clazz) {
384-
var interfaces = Arrays.stream(clazz.getInterfaces());
385-
var methods = interfaces.flatMap(c -> Arrays.stream(c.getDeclaredMethods()));
385+
private boolean implementsRunTimeInitializedInterface(Class<?> clazz) {
386+
EconomicSet<Class<?>> visited = EconomicSet.create();
387+
return Arrays.stream(clazz.getInterfaces()).anyMatch(c -> shouldInitializeInterfaceAtRunTime(c, visited));
388+
}
389+
390+
private boolean shouldInitializeInterfaceAtRunTime(Class<?> clazz, EconomicSet<Class<?>> visited) {
391+
if (visited.contains(clazz)) {
392+
// already visited
393+
return false;
394+
}
395+
GraalError.guarantee(clazz.isInterface(), "expected interface, got %s", clazz);
396+
visited.add(clazz);
397+
var methods = Arrays.stream(clazz.getDeclaredMethods());
386398
var types = methods.flatMap(m -> Stream.concat(Stream.of(m.getReturnType()), Arrays.stream(m.getParameterTypes())));
387-
return types.noneMatch(this::shouldInitializeAtRuntime);
399+
// check for initialize at run time
400+
if (types.anyMatch(this::shouldInitializeAtRuntime)) {
401+
return true;
402+
}
403+
// iterate super interfaces recursively
404+
return Arrays.stream(clazz.getInterfaces()).anyMatch(c -> shouldInitializeInterfaceAtRunTime(c, visited));
388405
}
389406

390407
private InitKind processInterfaces(Class<?> clazz, boolean memoizeEager, Set<Class<?>> earlyClassInitializerAnalyzedClasses) {

0 commit comments

Comments
 (0)