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) { public void methodReached(DependencyAgent agent, MethodDependency method) {
if (method.getReference().equals(CURRENT_THREAD)) { if (method.getReference().equals(CURRENT_THREAD)) {
method.use(); 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; thisAliased = true;
writer.append("var a").ws().append("=").ws().append("this;").ws(); 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") writer.appendClass(cls.getParentName()).append(".call(").append(thisAliased ? "a" : "this")
.append(");").softNewLine(); .append(");").softNewLine();
} }

View File

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

View File

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

View File

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