mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Further improvements to inliner
This commit is contained in:
parent
4de1c51e1a
commit
6790d724c7
|
@ -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();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user