Further improvements to inliner

This commit is contained in:
Alexey Andreev 2019-02-13 13:42:44 +03:00
parent 4de1c51e1a
commit 6790d724c7
5 changed files with 75 additions and 21 deletions

View File

@ -270,9 +270,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
public void methodReached(DependencyAgent agent, MethodDependency method) {
if (method.getReference().equals(CURRENT_THREAD)) {
method.use();
agent.linkMethod(new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class))
.use();
}
agent.linkMethod(new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class))
.use();
}
});
}

View File

@ -319,7 +319,7 @@ public class Renderer implements RenderingManager {
thisAliased = true;
writer.append("var a").ws().append("=").ws().append("this;").ws();
}
if (cls.getParentName() != null) {
if (!cls.getModifiers().contains(ElementModifier.INTERFACE) && cls.getParentName() != null) {
writer.appendClass(cls.getParentName()).append(".call(").append(thisAliased ? "a" : "this")
.append(");").softNewLine();
}

View File

@ -29,36 +29,42 @@ import org.teavm.model.instructions.SwitchTableEntryReader;
public class DefaultInliningStrategy implements InliningStrategy {
private final int complexityThreshold;
private final int depthThreshold;
private final int totalComplexityThreshold;
private final boolean onceUsedOnly;
public DefaultInliningStrategy(int complexityThreshold, int depthThreshold, boolean onceUsedOnly) {
public DefaultInliningStrategy(int complexityThreshold, int depthThreshold, int totalComplexityThreshold,
boolean onceUsedOnly) {
this.complexityThreshold = complexityThreshold;
this.depthThreshold = depthThreshold;
this.totalComplexityThreshold = totalComplexityThreshold;
this.onceUsedOnly = onceUsedOnly;
}
@Override
public InliningStep start(MethodReference method, ProgramReader program) {
int complexity = getComplexity(program);
if (complexity > complexityThreshold) {
Complexity complexity = getComplexity(program, null);
if (complexity.score > complexityThreshold) {
return null;
}
ComplexityHolder complexityHolder = new ComplexityHolder();
complexityHolder.complexity = complexity;
complexityHolder.complexity = complexity.score;
return new InliningStepImpl(complexityHolder);
}
static int getComplexity(ProgramReader program) {
private static Complexity getComplexity(ProgramReader program, InliningContext context) {
int complexity = 0;
ComplexityCounter counter = new ComplexityCounter();
ComplexityCounter counter = new ComplexityCounter(context);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i);
counter.complexity = 0;
block.readAllInstructions(counter);
complexity += block.instructionCount() + counter.complexity;
}
return complexity;
Complexity result = new Complexity();
result.score = complexity;
result.callsToUsedOnceMethods = counter.callsToUsedOnceMethods;
return result;
}
class InliningStepImpl implements InliningStep {
@ -70,16 +76,23 @@ public class DefaultInliningStrategy implements InliningStrategy {
@Override
public InliningStep tryInline(MethodReference method, ProgramReader program, InliningContext context) {
if (context.getDepth() > depthThreshold || (onceUsedOnly && !context.isUsedOnce(method))) {
if (context.getDepth() > depthThreshold) {
return null;
}
int complexity = getComplexity(program);
if (complexityHolder.complexity + complexity > complexityThreshold) {
Complexity complexity = getComplexity(program, context);
if (onceUsedOnly && !context.isUsedOnce(method)) {
if (complexity.callsToUsedOnceMethods || complexity.score > 1) {
return null;
}
}
if (complexity.score > complexityThreshold
|| complexityHolder.complexity + complexity.score > totalComplexityThreshold) {
return null;
}
complexityHolder.complexity += complexity;
complexityHolder.complexity += complexity.score;
return new InliningStepImpl(complexityHolder);
}
}
@ -89,7 +102,13 @@ public class DefaultInliningStrategy implements InliningStrategy {
}
static class ComplexityCounter extends AbstractInstructionReader {
InliningContext context;
int complexity;
boolean callsToUsedOnceMethods;
ComplexityCounter(InliningContext context) {
this.context = context;
}
@Override
public void nop() {
@ -99,9 +118,8 @@ public class DefaultInliningStrategy implements InliningStrategy {
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
complexity++;
if (instance != null) {
complexity++;
if (type == InvocationType.SPECIAL && context != null && context.isUsedOnce(method)) {
callsToUsedOnceMethods = true;
}
}
@ -133,4 +151,9 @@ public class DefaultInliningStrategy implements InliningStrategy {
complexity--;
}
}
static class Complexity {
int score;
boolean callsToUsedOnceMethods;
}
}

View File

@ -129,6 +129,26 @@ public class Inlining {
return usageCounter.methodUsageCount.getOrDefault(method, -1) != 0;
}
public void removeUsages(Program program) {
for (BasicBlock block : program.getBasicBlocks()) {
for (Instruction instruction : block) {
if (!(instruction instanceof InvokeInstruction)) {
continue;
}
InvokeInstruction invoke = (InvokeInstruction) instruction;
if (invoke.getType() != InvocationType.SPECIAL) {
continue;
}
int usageCount = usageCounter.methodUsageCount.getOrDefault(invoke.getMethod(), -1);
if (usageCount > 0) {
usageCounter.methodUsageCount.put(invoke.getMethod(), usageCount - 1);
}
}
}
}
public void apply(Program program, MethodReference method) {
depthsByBlock = new IntArrayList(program.basicBlockCount());
for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -195,7 +215,7 @@ public class Inlining {
splitBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
invoke.delete();
if (invoke.getInstance() == null || invoke.getMethod().getName().equals("<init>")) {
if (invoke.getMethod().getName().equals("<init>") || invoke.getInstance() == null) {
InitClassInstruction clinit = new InitClassInstruction();
clinit.setClassName(invoke.getMethod().getClassName());
block.add(clinit);
@ -211,6 +231,16 @@ public class Inlining {
Instruction insn = blockToInline.getFirstInstruction();
insn.delete();
inlineBlock.add(insn);
if (insn instanceof InvokeInstruction) {
InvokeInstruction invokeInsn = (InvokeInstruction) insn;
if (invokeInsn.getType() == InvocationType.SPECIAL) {
usageCount = usageCounter.methodUsageCount.getOrDefault(invokeInsn.getMethod(), -1);
if (usageCount >= 0) {
usageCounter.methodUsageCount.put(invokeInsn.getMethod(), usageCount + 1);
}
}
}
}
List<Phi> phis = new ArrayList<>(blockToInline.getPhis());

View File

@ -538,15 +538,15 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
private void inline(ListableClassHolderSource classes) {
if (optimizationLevel != TeaVMOptimizationLevel.ADVANCED) {
if (optimizationLevel != TeaVMOptimizationLevel.ADVANCED && optimizationLevel != TeaVMOptimizationLevel.FULL) {
return;
}
InliningStrategy inliningStrategy;
if (optimizationLevel == TeaVMOptimizationLevel.FULL) {
inliningStrategy = new DefaultInliningStrategy(17, 7, false);
inliningStrategy = new DefaultInliningStrategy(17, 7, 300, false);
} else {
inliningStrategy = new DefaultInliningStrategy(100, 5, true);
inliningStrategy = new DefaultInliningStrategy(100, 7, 300, true);
}
Inlining inlining = new Inlining(new ClassHierarchy(classes), dependencyAnalyzer, inliningStrategy,
@ -561,6 +561,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
if (method.getProgram() != null) {
if (!inlining.hasUsages(methodReference)) {
inlining.removeUsages(method.getProgram());
method.setProgram(null);
} else {
Program program = method.getProgram();