Limit depth of method analysis in class initializer analysis in order to avoid too deep stack (and therefore SOE)

This commit is contained in:
Alexey Andreev 2024-07-11 18:18:24 +02:00
parent 7efb3c97a0
commit 025801d385

View File

@ -43,6 +43,7 @@ import org.teavm.model.optimization.Devirtualization;
public class ClassInitializerAnalysis implements ClassInitializerInfo {
private static final MethodDescriptor CLINIT = new MethodDescriptor("<clinit>", void.class);
private static final int METHOD_ANALYSIS_DEPTH_THRESHOLD = 250;
private static final byte BEING_ANALYZED = 1;
private static final byte DYNAMIC = 2;
private static final byte STATIC = 3;
@ -55,6 +56,7 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
private List<? extends String> readonlyOrder = Collections.unmodifiableList(order);
private String currentAnalyzedClass;
private DependencyInfo dependencyInfo;
private int methodAnalysisDepth;
public ClassInitializerAnalysis(ListableClassReaderSource classes, ClassHierarchy hierarchy,
String entryPoint) {
@ -121,11 +123,15 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
var initializer = cls.getMethod(CLINIT);
var isStatic = true;
if (initializer != null) {
if (methodAnalysisDepth >= METHOD_ANALYSIS_DEPTH_THRESHOLD) {
isStatic = false;
} else {
var initializerInfo = analyzeMethod(initializer);
if (isDynamicInitializer(initializerInfo, className)) {
isStatic = false;
}
}
}
currentAnalyzedClass = previousClass;
if (classStatuses.get(className) == BEING_ANALYZED) {
@ -151,6 +157,7 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
}
private MethodInfo analyzeMethod(MethodReader method) {
methodAnalysisDepth++;
var methodInfo = methodInfoMap.get(method.getReference());
if (methodInfo == null) {
methodInfo = new MethodInfo(method.getReference());
@ -174,6 +181,7 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
methodInfo.complete = true;
}
--methodAnalysisDepth;
return methodInfo;
}
@ -264,12 +272,17 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
private void invokeMethod(MethodReference method) {
var cls = classes.get(method.getClassName());
if (cls != null) {
if (methodAnalysisDepth >= METHOD_ANALYSIS_DEPTH_THRESHOLD) {
methodInfo.anyFieldModified = true;
methodInfo.classesWithModifiedFields = null;
} else {
var methodReader = cls.getMethod(method.getDescriptor());
if (methodReader != null) {
analyzeCalledMethod(analyzeMethod(methodReader));
}
}
}
}
@Override
public void initClass(String className) {