Improve inlining performance by caching method complexity

This commit is contained in:
Alexey Andreev 2024-04-29 16:32:16 +02:00
parent d4f98a57d0
commit e48dfb27b0
3 changed files with 26 additions and 6 deletions

View File

@ -15,7 +15,9 @@
*/
package org.teavm.model.optimization;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ProgramReader;
@ -32,6 +34,7 @@ public class DefaultInliningStrategy implements InliningStrategy {
private final int totalComplexityThreshold;
private final boolean onceUsedOnly;
private int getComplexityDepth;
private Map<MethodReference, Complexity> complexityCache = new HashMap<>();
public DefaultInliningStrategy(int complexityThreshold, int depthThreshold, int totalComplexityThreshold,
boolean onceUsedOnly) {
@ -53,6 +56,20 @@ public class DefaultInliningStrategy implements InliningStrategy {
return new InliningStepImpl(complexityHolder);
}
@Override
public void methodChanged(MethodReference method) {
complexityCache.remove(method);
}
private Complexity getComplexity(MethodReference methodRef, InliningContext context) {
var result = complexityCache.get(methodRef);
if (result == null) {
result = getComplexity(context.getProgram(methodRef), context);
complexityCache.put(methodRef, result);
}
return result;
}
private Complexity getComplexity(ProgramReader program, InliningContext context) {
int complexity = 0;
ComplexityCounter counter = new ComplexityCounter(context);
@ -81,7 +98,7 @@ public class DefaultInliningStrategy implements InliningStrategy {
return null;
}
Complexity complexity = getComplexity(program, context);
Complexity complexity = getComplexity(method, context);
if (onceUsedOnly && !context.isUsedOnce(method)) {
if (complexity.callsToUsedOnceMethods || complexity.score > 1) {
return null;
@ -125,19 +142,18 @@ public class DefaultInliningStrategy implements InliningStrategy {
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
if (type == InvocationType.SPECIAL && context != null && context.isUsedOnce(method)) {
ProgramReader program = context.getProgram(method);
if (!isTrivialCall(program)) {
if (!isTrivialCall(method)) {
callsToUsedOnceMethods = true;
}
}
}
private boolean isTrivialCall(ProgramReader program) {
if (program == null || getComplexityDepth > 10) {
private boolean isTrivialCall(MethodReference methodRef) {
if (context.getProgram(methodRef) == null || getComplexityDepth > 10) {
return false;
}
getComplexityDepth++;
Complexity complexity = getComplexity(program, context);
Complexity complexity = getComplexity(methodRef, context);
getComplexityDepth--;
return complexity.score <= 1 && !complexity.callsToUsedOnceMethods;
}

View File

@ -175,6 +175,7 @@ public class Inlining {
instructionsToSkip = null;
new UnreachableBasicBlockEliminator().optimize(program);
strategy.methodChanged(method);
}
private boolean applyOnce(Program program, MethodReference method) {

View File

@ -20,4 +20,7 @@ import org.teavm.model.ProgramReader;
public interface InliningStrategy {
InliningStep start(MethodReference method, ProgramReader program);
default void methodChanged(MethodReference method) {
}
}