Adds unused variable elimination

This commit is contained in:
konsoletyper 2013-12-02 20:51:04 +04:00
parent ac0df0ca6b
commit 601fcf0824
10 changed files with 629 additions and 13 deletions

View File

@ -27,9 +27,6 @@ public class ObjectNativeGenerator implements Generator, DependencyPlugin {
case "hashCode": case "hashCode":
generateHashCode(context, writer); generateHashCode(context, writer);
break; break;
case "equals":
generateEquals(context, writer);
break;
case "clone": case "clone":
generateClone(context, writer); generateClone(context, writer);
break; break;
@ -84,11 +81,6 @@ public class ObjectNativeGenerator implements Generator, DependencyPlugin {
writer.append("return ").append(context.getParameterName(0)).append(".$id;").newLine(); writer.append("return ").append(context.getParameterName(0)).append(".$id;").newLine();
} }
private void generateEquals(GeneratorContext context, SourceWriter writer) {
writer.append("return ").append(context.getParameterName(0)).append(" == ")
.append(context.getParameterName(1)).append(";").newLine();
}
private void generateClone(GeneratorContext context, SourceWriter writer) { private void generateClone(GeneratorContext context, SourceWriter writer) {
writer.append("var copy = new ").append(context.getParameterName(0)).append(".$class();").newLine(); writer.append("var copy = new ").append(context.getParameterName(0)).append(".$class();").newLine();
writer.append("for (var field in obj) {").newLine().indent(); writer.append("for (var field in obj) {").newLine().indent();

View File

@ -28,8 +28,9 @@ public class TObject {
@GeneratedBy(ObjectNativeGenerator.class) @GeneratedBy(ObjectNativeGenerator.class)
public native int hashCode(); public native int hashCode();
@GeneratedBy(ObjectNativeGenerator.class) public boolean equals(TObject other) {
public native boolean equals(TObject other); return this == other;
}
@Rename("toString") @Rename("toString")
public native TString toString0(); public native TString toString0();

View File

@ -15,6 +15,7 @@ import org.teavm.javascript.Renderer;
import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ast.ClassNode;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.resource.ClasspathClassHolderSource; import org.teavm.model.resource.ClasspathClassHolderSource;
import org.teavm.optimization.ClassSetOptimizer;
/** /**
* *
@ -55,8 +56,10 @@ public class ClasslibTestGenerator {
dependencyChecker.addEntryPoint(methodRef); dependencyChecker.addEntryPoint(methodRef);
} }
dependencyChecker.checkDependencies(); dependencyChecker.checkDependencies();
dependencyChecker.cutUnachievableClasses(); ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses();
decompileClasses(dependencyChecker.getAchievableClasses()); ClassSetOptimizer optimizer = new ClassSetOptimizer();
optimizer.optimizeAll(classSet);
decompileClasses(classSet.getClassNames());
renderHead(); renderHead();
ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader(); ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader();
try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) { try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) {

View File

@ -289,6 +289,7 @@ public class DependencyChecker {
MutableClassHolderSource cutClasses = new MutableClassHolderSource(); MutableClassHolderSource cutClasses = new MutableClassHolderSource();
for (String className : achievableClasses.keySet()) { for (String className : achievableClasses.keySet()) {
ClassHolder classHolder = classSource.getClassHolder(className); ClassHolder classHolder = classSource.getClassHolder(className);
cutClasses.putClassHolder(classHolder);
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) { for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
MethodReference methodRef = new MethodReference(className, method.getDescriptor()); MethodReference methodRef = new MethodReference(className, method.getDescriptor());
if (!methodCache.getCachedPreimages().contains(methodRef)) { if (!methodCache.getCachedPreimages().contains(methodRef)) {

View File

@ -66,7 +66,7 @@ public class BasicBlock {
@Override @Override
public Instruction remove(int index) { public Instruction remove(int index) {
Instruction insn = super.remove(index); Instruction insn = instructions.remove(index);
insn.setBasicBlock(null); insn.setBasicBlock(null);
return insn; return insn;
} }

View File

@ -0,0 +1,27 @@
package org.teavm.optimization;
import java.util.Arrays;
import java.util.List;
import org.teavm.model.ClassHolder;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.MethodHolder;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClassSetOptimizer {
private List<MethodOptimization> optimizations = Arrays.<MethodOptimization>asList(
new UnusedVariableElimination());
public void optimizeAll(ListableClassHolderSource classSource) {
for (String className : classSource.getClassNames()) {
ClassHolder cls = classSource.getClassHolder(className);
for (MethodHolder method : cls.getMethods()) {
for (MethodOptimization optimization : optimizations) {
optimization.optimize(method);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
package org.teavm.optimization;
import org.teavm.model.MethodHolder;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface MethodOptimization {
void optimize(MethodHolder method);
}

View File

@ -0,0 +1,224 @@
package org.teavm.optimization;
import org.teavm.common.Graph;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class UnusedVariableElimination implements MethodOptimization {
@Override
public void optimize(MethodHolder method) {
if (method.getProgram() == null) {
return;
}
Graph graph = VariableUsageGraphBuilder.build(method.getProgram());
boolean[] escaping = VariableEscapeAnalyzer.findEscapingVariables(method.getProgram());
boolean[] used = new boolean[escaping.length];
int[] stack = new int[graph.size() * 2];
int top = 0;
for (int i = 0; i < used.length; ++i) {
if (escaping[i]) {
stack[top++] = i;
}
}
while (top > 0) {
int var = stack[--top];
if (used[var]) {
continue;
}
used[var] = true;
for (int arg : graph.incomingEdges(var)) {
if (!used[arg]) {
stack[top++] = arg;
}
}
}
Program program = method.getProgram();
InstructionOptimizer insnOptimizer = new InstructionOptimizer(used);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) {
insnOptimizer.eliminate = false;
block.getInstructions().get(j).acceptVisitor(insnOptimizer);
if (insnOptimizer.eliminate) {
block.getInstructions().remove(j--);
}
}
for (int j = 0; j < block.getPhis().size(); ++j) {
Phi phi = block.getPhis().get(j);
if (!used[phi.getReceiver().getIndex()]) {
block.getPhis().remove(j--);
}
}
}
}
private class InstructionOptimizer implements InstructionVisitor {
private boolean[] used;
boolean eliminate;
public InstructionOptimizer(boolean[] used) {
this.used = used;
}
private void requestUsage(Variable var) {
if (!used[var.getIndex()]) {
eliminate = true;
}
}
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(NullConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(IntegerConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(LongConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(FloatConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(DoubleConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(StringConstantInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(BinaryInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(NegateInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(AssignInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(CastInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(CastNumberInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(BranchingInstruction insn) {
}
@Override
public void visit(BinaryBranchingInstruction insn) {
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
}
@Override
public void visit(ExitInstruction insn) {
}
@Override
public void visit(RaiseInstruction insn) {
}
@Override
public void visit(ConstructArrayInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(ConstructInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(GetFieldInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(PutFieldInstruction insn) {
}
@Override
public void visit(ArrayLengthInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(CloneArrayInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(UnwrapArrayInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(GetElementInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
if (insn.getReceiver() != null && !used[insn.getReceiver().getIndex()]) {
insn.setReceiver(null);
}
}
@Override
public void visit(IsInstanceInstruction insn) {
requestUsage(insn.getReceiver());
}
}
}

View File

@ -0,0 +1,178 @@
package org.teavm.optimization;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.Program;
import org.teavm.model.Variable;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class VariableEscapeAnalyzer {
public static boolean[] findEscapingVariables(Program program) {
boolean[] escaping = new boolean[program.variableCount()];
InstructionAnalyzer analyzer = new InstructionAnalyzer(escaping);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(analyzer);
}
}
return escaping;
}
private static class InstructionAnalyzer implements InstructionVisitor {
private boolean[] escaping;
public InstructionAnalyzer(boolean[] escaping) {
this.escaping = escaping;
}
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
}
@Override
public void visit(NullConstantInstruction insn) {
}
@Override
public void visit(IntegerConstantInstruction insn) {
}
@Override
public void visit(LongConstantInstruction insn) {
}
@Override
public void visit(FloatConstantInstruction insn) {
}
@Override
public void visit(DoubleConstantInstruction insn) {
}
@Override
public void visit(StringConstantInstruction insn) {
}
@Override
public void visit(BinaryInstruction insn) {
}
@Override
public void visit(NegateInstruction insn) {
}
@Override
public void visit(AssignInstruction insn) {
}
@Override
public void visit(CastInstruction insn) {
}
@Override
public void visit(CastNumberInstruction insn) {
}
@Override
public void visit(BranchingInstruction insn) {
escaping[insn.getOperand().getIndex()] = true;
}
@Override
public void visit(BinaryBranchingInstruction insn) {
escaping[insn.getFirstOperand().getIndex()] = true;
escaping[insn.getSecondOperand().getIndex()] = true;
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
escaping[insn.getCondition().getIndex()] = true;
}
@Override
public void visit(ExitInstruction insn) {
if (insn.getValueToReturn() != null) {
escaping[insn.getValueToReturn().getIndex()] = true;
}
}
@Override
public void visit(RaiseInstruction insn) {
escaping[insn.getException().getIndex()] = true;
}
@Override
public void visit(ConstructArrayInstruction insn) {
}
@Override
public void visit(ConstructInstruction insn) {
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
}
@Override
public void visit(GetFieldInstruction insn) {
}
@Override
public void visit(PutFieldInstruction insn) {
if (insn.getInstance() != null) {
escaping[insn.getInstance().getIndex()] = true;
}
escaping[insn.getValue().getIndex()] = true;
}
@Override
public void visit(ArrayLengthInstruction insn) {
}
@Override
public void visit(CloneArrayInstruction insn) {
}
@Override
public void visit(UnwrapArrayInstruction insn) {
}
@Override
public void visit(GetElementInstruction insn) {
}
@Override
public void visit(PutElementInstruction insn) {
escaping[insn.getArray().getIndex()] = true;
escaping[insn.getIndex().getIndex()] = true;
escaping[insn.getValue().getIndex()] = true;
}
@Override
public void visit(InvokeInstruction insn) {
if (insn.getInstance() != null) {
escaping[insn.getInstance().getIndex()] = true;
}
for (Variable arg : insn.getArguments()) {
escaping[arg.getIndex()] = true;
}
}
@Override
public void visit(IsInstanceInstruction insn) {
}
}
}

View File

@ -0,0 +1,179 @@
package org.teavm.optimization;
import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class VariableUsageGraphBuilder {
public static Graph build(Program program) {
GraphBuilder builder = new GraphBuilder(program.variableCount());
InstructionAnalyzer analyzer = new InstructionAnalyzer(builder);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(analyzer);
}
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
}
}
}
return builder.build();
}
private static class InstructionAnalyzer implements InstructionVisitor {
private GraphBuilder builder;
public InstructionAnalyzer(GraphBuilder builder) {
this.builder = builder;
}
private void use(Variable receiver, Variable... arguments) {
for (Variable arg : arguments) {
builder.addEdge(arg.getIndex(), receiver.getIndex());
}
}
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
}
@Override
public void visit(NullConstantInstruction insn) {
}
@Override
public void visit(IntegerConstantInstruction insn) {
}
@Override
public void visit(LongConstantInstruction insn) {
}
@Override
public void visit(FloatConstantInstruction insn) {
}
@Override
public void visit(DoubleConstantInstruction insn) {
}
@Override
public void visit(StringConstantInstruction insn) {
}
@Override
public void visit(BinaryInstruction insn) {
use(insn.getReceiver(), insn.getFirstOperand(), insn.getSecondOperand());
}
@Override
public void visit(NegateInstruction insn) {
use(insn.getReceiver(), insn.getOperand());
}
@Override
public void visit(AssignInstruction insn) {
use(insn.getReceiver(), insn.getAssignee());
}
@Override
public void visit(CastInstruction insn) {
use(insn.getReceiver(), insn.getValue());
}
@Override
public void visit(CastNumberInstruction insn) {
use(insn.getReceiver(), insn.getValue());
}
@Override
public void visit(BranchingInstruction insn) {
}
@Override
public void visit(BinaryBranchingInstruction insn) {
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
}
@Override
public void visit(ExitInstruction insn) {
}
@Override
public void visit(RaiseInstruction insn) {
}
@Override
public void visit(ConstructArrayInstruction insn) {
use(insn.getReceiver(), insn.getSize());
}
@Override
public void visit(ConstructInstruction insn) {
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
use(insn.getReceiver(), insn.getDimensions().toArray(new Variable[0]));
}
@Override
public void visit(GetFieldInstruction insn) {
}
@Override
public void visit(PutFieldInstruction insn) {
}
@Override
public void visit(ArrayLengthInstruction insn) {
use(insn.getReceiver(), insn.getArray());
}
@Override
public void visit(CloneArrayInstruction insn) {
use(insn.getReceiver(), insn.getArray());
}
@Override
public void visit(UnwrapArrayInstruction insn) {
use(insn.getReceiver(), insn.getArray());
}
@Override
public void visit(GetElementInstruction insn) {
use(insn.getReceiver(), insn.getArray(), insn.getIndex());
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
}
@Override
public void visit(IsInstanceInstruction insn) {
use(insn.getReceiver(), insn.getValue());
}
}
}