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

View File

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

View File

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