All tests pass with register allocation

This commit is contained in:
konsoletyper 2014-01-27 16:02:23 +04:00
parent 94fe8a0acf
commit c9a891d9cd
9 changed files with 47 additions and 190 deletions

View File

@ -52,7 +52,7 @@
</goals> </goals>
<phase>process-test-classes</phase> <phase>process-test-classes</phase>
<configuration> <configuration>
<minifying>true</minifying> <minifying>false</minifying>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>

View File

@ -201,7 +201,7 @@ public class Decompiler {
methodNode.getVariables().add(program.variableAt(i).getRegister()); methodNode.getVariables().add(program.variableAt(i).getRegister());
} }
Optimizer optimizer = new Optimizer(); Optimizer optimizer = new Optimizer();
optimizer.optimize(methodNode); optimizer.optimize(methodNode, method.getProgram());
return methodNode; return methodNode;
} }

View File

@ -37,7 +37,7 @@ public class JavascriptBuilder {
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private ClassLoader classLoader; private ClassLoader classLoader;
private boolean minifying = true; private boolean minifying = true;
private boolean bytecodeLogging; private boolean bytecodeLogging = true;
private OutputStream logStream = System.out; private OutputStream logStream = System.out;
private Map<String, JavascriptEntryPoint> entryPoints = new HashMap<>(); private Map<String, JavascriptEntryPoint> entryPoints = new HashMap<>();
private Map<String, String> exportedClasses = new HashMap<>(); private Map<String, String> exportedClasses = new HashMap<>();

View File

@ -16,8 +16,7 @@
package org.teavm.javascript; package org.teavm.javascript;
import org.teavm.javascript.ast.RegularMethodNode; import org.teavm.javascript.ast.RegularMethodNode;
import org.teavm.javascript.ast.Statement; import org.teavm.model.Program;
import org.teavm.model.MethodHolder;
/** /**
@ -25,17 +24,9 @@ import org.teavm.model.MethodHolder;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class Optimizer { public class Optimizer {
public Statement optimize(MethodHolder method, Statement statement) { public void optimize(RegularMethodNode method, Program program) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getProgram().variableCount());
statement.acceptVisitor(stats);
OptimizingVisitor optimizer = new OptimizingVisitor(stats);
statement.acceptVisitor(optimizer);
return optimizer.resultStmt;
}
public void optimize(RegularMethodNode method) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size()); ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
method.getBody().acceptVisitor(stats); stats.analyze(program);
OptimizingVisitor optimizer = new OptimizingVisitor(stats); OptimizingVisitor optimizer = new OptimizingVisitor(stats);
method.getBody().acceptVisitor(optimizer); method.getBody().acceptVisitor(optimizer);
method.setBody(optimizer.resultStmt); method.setBody(optimizer.resultStmt);

View File

@ -377,7 +377,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
WhileStatement result = new WhileStatement(); WhileStatement result = new WhileStatement();
result.setId(statement.getId()); result.setId(statement.getId());
visitIdentified(statement, result); visitIdentified(statement, result);
List<Statement> statements = processSequence(statement.getBody(), false); List<Statement> statements = processSequence(statement.getBody(), true);
if (statement.getCondition() != null) { if (statement.getCondition() != null) {
statement.getCondition().acceptVisitor(this); statement.getCondition().acceptVisitor(this);
result.setCondition(resultExpr); result.setCondition(resultExpr);

View File

@ -15,13 +15,15 @@
*/ */
package org.teavm.javascript; package org.teavm.javascript;
import org.teavm.javascript.ast.*; import org.teavm.model.*;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.UsageExtractor;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
class ReadWriteStatsBuilder implements StatementVisitor, ExprVisitor { class ReadWriteStatsBuilder {
public int[] reads; public int[] reads;
public int[] writes; public int[] writes;
@ -30,169 +32,27 @@ class ReadWriteStatsBuilder implements StatementVisitor, ExprVisitor {
writes = new int[variableCount]; writes = new int[variableCount];
} }
@Override public void analyze(Program program) {
public void visit(BinaryExpr expr) { DefinitionExtractor defExtractor = new DefinitionExtractor();
expr.getFirstOperand().acceptVisitor(this); UsageExtractor useExtractor = new UsageExtractor();
expr.getSecondOperand().acceptVisitor(this); for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(defExtractor);
insn.acceptVisitor(useExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
writes[var.getIndex()]++;
} }
for (Variable var : useExtractor.getUsedVariables()) {
@Override reads[var.getIndex()]++;
public void visit(UnaryExpr expr) {
expr.getOperand().acceptVisitor(this);
}
@Override
public void visit(ConditionalExpr expr) {
expr.getCondition().acceptVisitor(this);
expr.getConsequent().acceptVisitor(this);
expr.getAlternative().acceptVisitor(this);
}
@Override
public void visit(ConstantExpr expr) {
}
@Override
public void visit(VariableExpr expr) {
reads[expr.getIndex()]++;
}
@Override
public void visit(SubscriptExpr expr) {
expr.getArray().acceptVisitor(this);
expr.getIndex().acceptVisitor(this);
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
}
@Override
public void visit(InvocationExpr expr) {
for (Expr arg : expr.getArguments()) {
arg.acceptVisitor(this);
} }
} }
for (Phi phi : block.getPhis()) {
@Override writes[phi.getReceiver().getIndex()] += phi.getIncomings().size();
public void visit(QualificationExpr expr) { for (Incoming incoming : phi.getIncomings()) {
expr.getQualified().acceptVisitor(this); reads[incoming.getValue().getIndex()]++;
}
@Override
public void visit(NewExpr expr) {
}
@Override
public void visit(NewArrayExpr expr) {
expr.getLength().acceptVisitor(this);
}
@Override
public void visit(NewMultiArrayExpr expr) {
for (Expr dimension : expr.getDimensions()) {
dimension.acceptVisitor(this);
} }
} }
@Override
public void visit(InstanceOfExpr expr) {
expr.getExpr().acceptVisitor(this);
}
@Override
public void visit(StaticClassExpr expr) {
}
@Override
public void visit(AssignmentStatement statement) {
if (statement.getLeftValue() != null) {
if (statement.getLeftValue() instanceof VariableExpr) {
VariableExpr leftVar = (VariableExpr)statement.getLeftValue();
writes[leftVar.getIndex()]++;
} else {
statement.getLeftValue().acceptVisitor(this);
} }
} }
statement.getRightValue().acceptVisitor(this);
}
@Override
public void visit(SequentialStatement statement) {
for (Statement part : statement.getSequence()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(ConditionalStatement statement) {
statement.getCondition().acceptVisitor(this);
statement.getConsequent().acceptVisitor(this);
if (statement.getAlternative() != null) {
statement.getAlternative().acceptVisitor(this);
}
}
@Override
public void visit(SwitchStatement statement) {
statement.getValue().acceptVisitor(this);
for (SwitchClause clause : statement.getClauses()) {
clause.getStatement().acceptVisitor(this);
}
if (statement.getDefaultClause() != null) {
statement.getDefaultClause().acceptVisitor(this);
}
}
@Override
public void visit(WhileStatement statement) {
if (statement.getCondition() != null) {
statement.getCondition().acceptVisitor(this);
}
for (Statement part : statement.getBody()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(BlockStatement statement) {
for (Statement part : statement.getBody()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(ForStatement statement) {
}
@Override
public void visit(BreakStatement statement) {
}
@Override
public void visit(ContinueStatement statement) {
}
@Override
public void visit(ReturnStatement statement) {
if (statement.getResult() != null) {
statement.getResult().acceptVisitor(this);
}
}
@Override
public void visit(ThrowStatement statement) {
statement.getException().acceptVisitor(this);
}
@Override
public void visit(IncrementStatement statement) {
reads[statement.getVar()]++;
writes[statement.getVar()]++;
}
@Override
public void visit(InitClassStatement statement) {
}
} }

View File

@ -35,13 +35,11 @@ class GraphColorer {
classMembers.get(cls).add(i); classMembers.get(cls).add(i);
} }
for (int i = 0; i < colors.length; ++i) { for (int i = 0; i < colors.length; ++i) {
int color = colors[i]; if (colors[i] >= 0) {
if (color != -1) {
int cls = classes[i]; int cls = classes[i];
for (int member : classMembers.get(cls)) { for (int member : classMembers.get(cls)) {
colors[member] = color; colors[member] = colors[i];
} }
classMembers.get(cls).clear();
} }
} }
BitSet usedColors = new BitSet(); BitSet usedColors = new BitSet();
@ -49,15 +47,18 @@ class GraphColorer {
if (colors[v] >= 0) { if (colors[v] >= 0) {
continue; continue;
} }
int cls = classes[v];
usedColors.clear(); usedColors.clear();
usedColors.set(0); usedColors.set(0);
for (int succ : graph.outgoingEdges(v)) { for (int member : classMembers.get(cls)) {
for (int succ : graph.outgoingEdges(member)) {
if (colors[succ] >= 0) { if (colors[succ] >= 0) {
usedColors.set(colors[succ]); usedColors.set(colors[succ]);
} }
} }
}
int color = usedColors.nextClearBit(0); int color = usedColors.nextClearBit(0);
for (int member : classMembers.get(classes[v])) { for (int member : classMembers.get(cls)) {
colors[member] = color; colors[member] = color;
} }
} }

View File

@ -25,7 +25,7 @@ import org.teavm.model.*;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
class InterferenceGraphBuilder { class InterferenceGraphBuilder {
public Graph build(Program program, LivenessAnalyzer liveness) { public Graph build(Program program, int paramCount, LivenessAnalyzer liveness) {
List<Set<Integer>> edges = new ArrayList<>(); List<Set<Integer>> edges = new ArrayList<>();
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
edges.add(new HashSet<Integer>()); edges.add(new HashSet<Integer>());
@ -64,6 +64,11 @@ class InterferenceGraphBuilder {
live.add(var.getIndex()); live.add(var.getIndex());
} }
} }
if (block.getIndex() == 0) {
for (int j = 0; j <= paramCount; ++j) {
edges.get(j).addAll(live);
}
}
BitSet liveIn = liveness.liveIn(i); BitSet liveIn = liveness.liveIn(i);
live = new HashSet<>(); live = new HashSet<>();
for (int j = 0; j < liveOut.length(); ++j) { for (int j = 0; j < liveOut.length(); ++j) {

View File

@ -34,7 +34,7 @@ public class RegisterAllocator {
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder(); InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
LivenessAnalyzer liveness = new LivenessAnalyzer(); LivenessAnalyzer liveness = new LivenessAnalyzer();
liveness.analyze(program); liveness.analyze(program);
Graph interferenceGraph = interferenceBuilder.build(program, liveness); Graph interferenceGraph = interferenceBuilder.build(program, method.parameterCount(), liveness);
DisjointSet congruenceClasses = buildPhiCongruenceClasses(program); DisjointSet congruenceClasses = buildPhiCongruenceClasses(program);
removeRedundantCopies(program, phiArgsCopies, interferenceGraph, congruenceClasses); removeRedundantCopies(program, phiArgsCopies, interferenceGraph, congruenceClasses);
int[] classArray = congruenceClasses.pack(program.variableCount()); int[] classArray = congruenceClasses.pack(program.variableCount());