From 6790d724c79167e9eb6ac5fe630ac36648d95aba Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 13 Feb 2019 13:42:44 +0300 Subject: [PATCH] Further improvements to inliner --- .../backend/javascript/JavaScriptTarget.java | 4 +- .../javascript/rendering/Renderer.java | 2 +- .../optimization/DefaultInliningStrategy.java | 51 ++++++++++++++----- .../teavm/model/optimization/Inlining.java | 32 +++++++++++- core/src/main/java/org/teavm/vm/TeaVM.java | 7 +-- 5 files changed, 75 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index f9205db94..834664a8e 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -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(); } }); } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 752128d6d..f15700597 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -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(); } diff --git a/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java b/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java index 8314f038c..452e3efae 100644 --- a/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java +++ b/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java @@ -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 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; + } } diff --git a/core/src/main/java/org/teavm/model/optimization/Inlining.java b/core/src/main/java/org/teavm/model/optimization/Inlining.java index 2c769497c..146d5958e 100644 --- a/core/src/main/java/org/teavm/model/optimization/Inlining.java +++ b/core/src/main/java/org/teavm/model/optimization/Inlining.java @@ -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("")) { + if (invoke.getMethod().getName().equals("") || 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 phis = new ArrayList<>(blockToInline.getPhis()); diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index 2be2e7992..dd82b7dff 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -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();