New AST optimization algorithm

This commit is contained in:
konsoletyper 2014-01-29 17:35:27 +04:00
parent d93883296e
commit 16d11909ea
14 changed files with 376 additions and 443 deletions

View File

@ -53,7 +53,7 @@
<phase>process-test-classes</phase>
<configuration>
<minifying>false</minifying>
<numThreads>0</numThreads>
<numThreads>1</numThreads>
</configuration>
</execution>
</executions>

View File

@ -0,0 +1,107 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.javascript;
import java.util.HashMap;
import java.util.Map;
import org.teavm.javascript.ast.*;
/**
*
* @author Alexey Andreev
*/
class BlockRefCountVisitor implements StatementVisitor {
Map<IdentifiedStatement, Integer> refs = new HashMap<>();
@Override
public void visit(AssignmentStatement statement) {
}
@Override
public void visit(SequentialStatement statement) {
for (Statement part : statement.getSequence()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(ConditionalStatement statement) {
for (Statement stmt : statement.getConsequent()) {
stmt.acceptVisitor(this);
}
for (Statement stmt : statement.getAlternative()) {
stmt.acceptVisitor(this);
}
}
@Override
public void visit(SwitchStatement statement) {
for (SwitchClause clause : statement.getClauses()) {
for (Statement part : clause.getBody()) {
part.acceptVisitor(this);
}
}
for (Statement part : statement.getDefaultClause()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(WhileStatement statement) {
refs.put(statement, 0);
for (Statement part : statement.getBody()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(BlockStatement statement) {
refs.put(statement, 0);
for (Statement part : statement.getBody()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(ForStatement statement) {
}
@Override
public void visit(BreakStatement statement) {
refs.put(statement.getTarget(), refs.get(statement.getTarget()) + 1);
}
@Override
public void visit(ContinueStatement statement) {
refs.put(statement.getTarget(), refs.get(statement.getTarget()) + 1);
}
@Override
public void visit(ReturnStatement statement) {
}
@Override
public void visit(ThrowStatement statement) {
}
@Override
public void visit(IncrementStatement statement) {
}
@Override
public void visit(InitClassStatement statement) {
}
}

View File

@ -1,225 +0,0 @@
/*
* Copyright 2012 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.javascript;
import java.util.List;
import java.util.Map;
import org.teavm.javascript.ast.*;
/**
*
* @author Alexey Andreev
*/
class ConditionalOptimizer {
public Map<IdentifiedStatement, Integer> referencedStatements;
public ReadWriteStatsBuilder stats;
public Statement tryOptimizeElse(BlockStatement stmt) {
if (stmt.getBody().isEmpty()) {
return stmt;
}
if (!(stmt.getBody().get(0) instanceof ConditionalStatement)) {
return stmt;
}
ConditionalStatement condStmt = (ConditionalStatement)stmt.getBody().get(0);
if (condStmt.getAlternative() != null) {
return stmt;
}
if (!(condStmt.getConsequent() instanceof SequentialStatement)) {
return stmt;
}
SequentialStatement condBody = (SequentialStatement)condStmt.getConsequent();
if (condBody.getSequence().isEmpty()) {
return stmt;
}
Statement lastStmt = condBody.getSequence().get(condBody.getSequence().size() - 1);
if (!(lastStmt instanceof BreakStatement)) {
return stmt;
}
BreakStatement breakStmt = (BreakStatement)lastStmt;
if (breakStmt.getTarget() != stmt) {
return stmt;
}
SequentialStatement altBody = new SequentialStatement();
for (int j = 1; j < stmt.getBody().size(); ++j) {
altBody.getSequence().add(stmt.getBody().get(j));
}
if (!altBody.getSequence().isEmpty()) {
condStmt.setAlternative(altBody.getSequence().size() != 1 ?
altBody : altBody.getSequence().get(0));
}
condBody.getSequence().remove(condBody.getSequence().size() - 1);
if (condBody.getSequence().size() == 1) {
condStmt.setConsequent(condBody.getSequence().get(0));
}
stmt.getBody().clear();
stmt.getBody().add(condStmt);
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
if (referencedStatements.get(stmt) > 0) {
return stmt;
} else {
return tryMakeInline(condStmt);
}
}
public Statement tryOptimize(BlockStatement stmt) {
for (int i = 0; i < stmt.getBody().size(); ++i) {
if (stmt.getBody().isEmpty()) {
continue;
}
if (!(stmt.getBody().get(i) instanceof ConditionalStatement)) {
continue;
}
ConditionalStatement condStmt = (ConditionalStatement)stmt.getBody().get(i);
if (condStmt.getAlternative() != null) {
continue;
}
if (!(condStmt.getConsequent() instanceof BreakStatement)) {
continue;
}
BreakStatement breakStmt = (BreakStatement)condStmt.getConsequent();
if (breakStmt.getTarget() != stmt) {
continue;
}
stmt.getBody().remove(i);
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
ConditionalStatement newCond = new ConditionalStatement();
newCond.setCondition(ExprOptimizer.invert(condStmt.getCondition()));
List<Statement> remaining = stmt.getBody().subList(i, stmt.getBody().size());
if (remaining.size() == 1) {
newCond.setConsequent(remaining.get(0));
} else {
SequentialStatement newConsequent = new SequentialStatement();
newConsequent.getSequence().addAll(remaining);
newCond.setConsequent(newConsequent);
}
remaining.clear();
stmt.getBody().add(newCond);
if (referencedStatements.get(stmt) == 0) {
SequentialStatement flat = new SequentialStatement();
flat.getSequence().addAll(stmt.getBody());
return flat;
} else {
--i;
}
}
return stmt;
}
public void tryOptimize(WhileStatement stmt) {
if (stmt.getBody().isEmpty()) {
return;
}
if (!(stmt.getBody().get(0) instanceof ConditionalStatement)) {
return;
}
if (stmt.getCondition() != null) {
return;
}
ConditionalStatement condStmt = (ConditionalStatement)stmt.getBody().get(0);
if (condStmt.getAlternative() != null) {
return;
}
if (!(condStmt.getConsequent() instanceof BreakStatement)) {
return;
}
BreakStatement breakStmt = (BreakStatement)condStmt.getConsequent();
if (breakStmt.getTarget() != stmt) {
return;
}
stmt.getBody().remove(0);
stmt.setCondition(ExprOptimizer.invert(condStmt.getCondition()));
}
public Statement tryMakeInline(ConditionalStatement stmt) {
if (!(stmt.getConsequent() instanceof AssignmentStatement) ||
!(stmt.getAlternative() instanceof AssignmentStatement)) {
return stmt;
}
AssignmentStatement consequent = (AssignmentStatement)stmt.getConsequent();
AssignmentStatement alternative = (AssignmentStatement)stmt.getAlternative();
if (!(consequent.getLeftValue() instanceof VariableExpr) ||
!(alternative.getLeftValue() instanceof VariableExpr)) {
return stmt;
}
VariableExpr consequentLeft = (VariableExpr)consequent.getLeftValue();
VariableExpr alternativeLeft = (VariableExpr)alternative.getLeftValue();
if (consequentLeft.getIndex() != alternativeLeft.getIndex()) {
return stmt;
}
AssignmentStatement result = new AssignmentStatement();
result.setLeftValue(consequentLeft);
ConditionalExpr rightValue = new ConditionalExpr();
rightValue.setCondition(stmt.getCondition());
rightValue.setConsequent(consequent.getRightValue());
rightValue.setAlternative(alternative.getRightValue());
result.setRightValue(rightValue);
stats.writes[consequentLeft.getIndex()]--;
return result;
}
public Statement tryOptimizeSwitch(BlockStatement stmt) {
if (stmt.getBody().size() < 2) {
return stmt;
}
if (!(stmt.getBody().get(0) instanceof SwitchStatement)) {
return stmt;
}
SwitchStatement switchStmt = (SwitchStatement)stmt.getBody().get(0);
Statement last = stmt.getBody().get(stmt.getBody().size() - 1);
if (!(last instanceof BreakStatement) && !(last instanceof ContinueStatement) &&
!(last instanceof ReturnStatement) && !(last instanceof ThrowStatement)) {
return stmt;
}
SequentialStatement seqStmt = new SequentialStatement();
for (int i = 1; i < stmt.getBody().size(); ++i) {
seqStmt.getSequence().add(stmt.getBody().get(i));
}
int count = referencedStatements.get(stmt);
ReferenceCountingVisitor refCounter = new ReferenceCountingVisitor(stmt);
switchStmt.acceptVisitor(refCounter);
if (count > refCounter.count) {
return stmt;
}
referencedStatements.put(stmt, 0);
for (SwitchClause clause : switchStmt.getClauses()) {
if (!(clause.getStatement() instanceof BreakStatement)) {
continue;
}
BreakStatement breakStmt = (BreakStatement)clause.getStatement();
if (breakStmt.getTarget() == stmt) {
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
Integer switchRefs = referencedStatements.get(switchStmt);
referencedStatements.put(switchStmt, (switchRefs != null ? switchRefs : 0) + 1);
breakStmt.setTarget(switchStmt);
} else if (breakStmt.getTarget() == switchStmt) {
clause.setStatement(seqStmt);
}
}
if (switchStmt.getDefaultClause() instanceof BreakStatement) {
BreakStatement breakStmt = (BreakStatement)switchStmt.getDefaultClause();
if (breakStmt.getTarget() == stmt) {
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
Integer switchRefs = referencedStatements.get(switchStmt);
referencedStatements.put(switchStmt, (switchRefs != null ? switchRefs : 0) + 1);
breakStmt.setTarget(switchStmt);
} else if (breakStmt.getTarget() == switchStmt) {
switchStmt.setDefaultClause(seqStmt);
}
}
return switchStmt;
}
}

View File

@ -27,7 +27,10 @@ public class Optimizer {
public void optimize(RegularMethodNode method, Program program) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(program);
BlockRefCountVisitor refsCounter = new BlockRefCountVisitor();
method.getBody().acceptVisitor(refsCounter);
OptimizingVisitor optimizer = new OptimizingVisitor(stats);
optimizer.referencedStatements = refsCounter.refs;
method.getBody().acceptVisitor(optimizer);
method.setBody(optimizer.resultStmt);
int paramCount = method.getReference().parameterCount();

View File

@ -26,15 +26,11 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public Expr resultExpr;
public Statement resultStmt;
private ReadWriteStatsBuilder stats;
private Map<IdentifiedStatement, IdentifiedStatement> copies = new HashMap<>();
private Map<IdentifiedStatement, Integer> referencedStatements = new HashMap<>();
private ConditionalOptimizer conditionalOptimizer = new ConditionalOptimizer();
Map<IdentifiedStatement, Integer> referencedStatements = new HashMap<>();
private List<Statement> resultSequence;
public OptimizingVisitor(ReadWriteStatsBuilder stats) {
this.stats = stats;
conditionalOptimizer.referencedStatements = referencedStatements;
conditionalOptimizer.stats = stats;
}
private static boolean isZero(Expr expr) {
@ -83,14 +79,17 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
break;
}
}
resultExpr = Expr.binary(expr.getOperation(), a, b);
expr.setFirstOperand(a);
expr.setSecondOperand(b);
resultExpr = expr;
}
@Override
public void visit(UnaryExpr expr) {
expr.getOperand().acceptVisitor(this);
Expr operand = resultExpr;
resultExpr = Expr.unary(expr.getOperation(), operand);
expr.setOperand(operand);
resultExpr = expr;
}
@Override
@ -101,22 +100,21 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
Expr consequent = resultExpr;
expr.getAlternative().acceptVisitor(this);
Expr alternative = resultExpr;
ConditionalExpr result = new ConditionalExpr();
result.setCondition(cond);
result.setConsequent(consequent);
result.setAlternative(alternative);
resultExpr = result;
expr.setCondition(cond);
expr.setConsequent(consequent);
expr.setAlternative(alternative);
resultExpr = expr;
}
@Override
public void visit(ConstantExpr expr) {
resultExpr = Expr.constant(expr.getValue());
resultExpr = expr;
}
@Override
public void visit(VariableExpr expr) {
int index = expr.getIndex();
resultExpr = Expr.var(index);
resultExpr = expr;
if (stats.reads[index] != 1 || stats.writes[index] != 1) {
return;
}
@ -144,16 +142,17 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
Expr index = resultExpr;
expr.getArray().acceptVisitor(this);
Expr array = resultExpr;
resultExpr = Expr.subscript(array, index);
expr.setArray(array);
expr.setIndex(index);
resultExpr = expr;
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
Expr arrayExpr = resultExpr;
UnwrapArrayExpr result = new UnwrapArrayExpr(expr.getElementType());
result.setArray(arrayExpr);
resultExpr = result;
expr.setArray(arrayExpr);
resultExpr = expr;
}
@Override
@ -163,20 +162,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
expr.getArguments().get(i).acceptVisitor(this);
args[i] = resultExpr;
}
switch (expr.getType()) {
case STATIC:
resultExpr = Expr.invokeStatic(expr.getMethod(), args);
break;
case DYNAMIC:
resultExpr = Expr.invoke(expr.getMethod(), args[0], Arrays.copyOfRange(args, 1, args.length));
break;
case SPECIAL:
resultExpr = Expr.invokeSpecial(expr.getMethod(), args[0], Arrays.copyOfRange(args, 1, args.length));
break;
case CONSTRUCTOR:
resultExpr = Expr.constructObject(expr.getMethod(), args);
break;
for (int i = 0; i < args.length; ++i) {
expr.getArguments().set(i, args[i]);
}
resultExpr = expr;
}
private boolean tryApplyConstructor(InvocationExpr expr) {
@ -220,42 +209,43 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public void visit(QualificationExpr expr) {
expr.getQualified().acceptVisitor(this);
Expr qualified = resultExpr;
resultExpr = Expr.qualify(qualified, expr.getField());
expr.setQualified(qualified);
resultExpr = expr;
}
@Override
public void visit(NewExpr expr) {
resultExpr = Expr.createObject(expr.getConstructedClass());
resultExpr = expr;
}
@Override
public void visit(NewArrayExpr expr) {
expr.getLength().acceptVisitor(this);
Expr length = resultExpr;
resultExpr = Expr.createArray(expr.getType(), length);
expr.setLength(length);
resultExpr = expr;
}
@Override
public void visit(NewMultiArrayExpr expr) {
NewMultiArrayExpr result = new NewMultiArrayExpr();
result.setType(expr.getType());
for (Expr dimension : expr.getDimensions()) {
for (int i = 0; i < expr.getDimensions().size(); ++i) {
Expr dimension = expr.getDimensions().get(i);
dimension.acceptVisitor(this);
result.getDimensions().add(resultExpr);
expr.getDimensions().set(i, resultExpr);
}
resultExpr = result;
resultExpr = expr;
}
@Override
public void visit(InstanceOfExpr expr) {
expr.getExpr().acceptVisitor(this);
Expr value = resultExpr;
resultExpr = Expr.instanceOf(value, expr.getType());
expr.setExpr(resultExpr);
resultExpr = expr;
}
@Override
public void visit(StaticClassExpr expr) {
resultExpr = Expr.staticClass(expr.getType());
resultExpr = expr;
}
@Override
@ -266,7 +256,8 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
tryApplyConstructor((InvocationExpr)resultExpr)) {
resultStmt = new SequentialStatement();
} else {
resultStmt = Statement.assign(null, resultExpr);
statement.setRightValue(resultExpr);
resultStmt = statement;
}
} else {
statement.getRightValue().acceptVisitor(this);
@ -276,7 +267,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
statement.getLeftValue().acceptVisitor(this);
left = resultExpr;
}
resultStmt = Statement.assign(left, right);
statement.setLeftValue(left);
statement.setRightValue(right);
resultStmt = statement;
}
}
@ -286,14 +279,21 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
if (strict) {
resultSequence = result;
}
for (Statement part : statements) {
outer: for (int i = 0; i < statements.size(); ++i) {
Statement part = statements.get(i);
part.acceptVisitor(this);
if (resultStmt != null) {
List<Statement> newStatements = new ArrayList<>();
if (resultStmt instanceof SequentialStatement) {
newStatements.addAll(((SequentialStatement)resultStmt).getSequence());
} else {
newStatements.add(resultStmt);
}
for (int j = 0; j < newStatements.size(); ++j) {
Statement newStatement = newStatements.get(j);
resultSequence = result;
if (resultStmt instanceof SequentialStatement) {
result.addAll(((SequentialStatement)resultStmt).getSequence());
} else {
result.add(resultStmt);
result.add(newStatement);
if (newStatement instanceof BreakStatement) {
break outer;
}
}
}
@ -301,118 +301,168 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
return result;
}
private void eliminateRedundantBreaks(List<Statement> statements, Set<IdentifiedStatement> currentExits,
Set<IdentifiedStatement> exits) {
if (statements.isEmpty()) {
return;
}
Statement last = statements.get(statements.size() - 1);
if (last instanceof BreakStatement) {
IdentifiedStatement target = ((BreakStatement)last).getTarget();
if (exits.contains(target)) {
statements.remove(statements.size() - 1);
}
}
if (statements.isEmpty()) {
return;
}
Set<IdentifiedStatement> nestedExits = new HashSet<>();
nestedExits.addAll(currentExits);
for (int i = 0; i < statements.size(); ++i) {
if (i == statements.size() - 1) {
nestedExits.addAll(exits);
}
Statement stmt = statements.get(i);
if (stmt instanceof ConditionalStatement) {
ConditionalStatement cond = (ConditionalStatement)stmt;
last = cond.getConsequent().get(cond.getConsequent().size() - 1);
if (last instanceof BreakStatement) {
BreakStatement breakStmt = (BreakStatement)last;
if (currentExits.contains(breakStmt.getTarget()) || exits.contains(breakStmt.getTarget())) {
int refs = referencedStatements.get(breakStmt.getTarget());
referencedStatements.put(breakStmt.getTarget(), refs - 1);
cond.getConsequent().remove(cond.getConsequent().size() - 1);
List<Statement> remaining = statements.subList(i + 1, statements.size());
cond.getAlternative().addAll(remaining);
remaining.clear();
visit(cond);
if (resultStmt == cond) {
eliminateRedundantBreaks(cond.getConsequent(),
Collections.<IdentifiedStatement>emptySet(), nestedExits);
eliminateRedundantBreaks(cond.getAlternative(),
Collections.<IdentifiedStatement>emptySet(), nestedExits);
} else {
statements.set(i, resultStmt);
}
break;
}
}
last = cond.getAlternative().isEmpty() ? null :
cond.getAlternative().get(cond.getAlternative().size() - 1);
if (last instanceof BreakStatement) {
BreakStatement breakStmt = (BreakStatement)last;
if (currentExits.contains(breakStmt.getTarget()) || exits.contains(breakStmt.getTarget())) {
int refs = referencedStatements.get(breakStmt.getTarget());
referencedStatements.put(breakStmt.getTarget(), refs - 1);
cond.getAlternative().remove(cond.getConsequent().size() - 1);
List<Statement> remaining = statements.subList(i + 1, statements.size());
cond.getConsequent().addAll(remaining);
remaining.clear();
visit(cond);
if (resultStmt == cond) {
eliminateRedundantBreaks(cond.getConsequent(),
Collections.<IdentifiedStatement>emptySet(), nestedExits);
eliminateRedundantBreaks(cond.getAlternative(),
Collections.<IdentifiedStatement>emptySet(), nestedExits);
}
statements.set(i, resultStmt);
break;
}
}
} else if (stmt instanceof BlockStatement) {
BlockStatement nestedBlock = (BlockStatement)stmt;
eliminateRedundantBreaks(nestedBlock.getBody(),
Collections.<IdentifiedStatement>singleton(nestedBlock), nestedExits);
} else if (stmt instanceof WhileStatement) {
WhileStatement whileStmt = (WhileStatement)stmt;
eliminateRedundantBreaks(whileStmt.getBody(), Collections.<IdentifiedStatement>emptySet(),
Collections.<IdentifiedStatement>emptySet());
} else if (stmt instanceof SwitchStatement) {
SwitchStatement switchStmt = (SwitchStatement)stmt;
for (SwitchClause clause : switchStmt.getClauses()) {
eliminateRedundantBreaks(clause.getBody(), Collections.<IdentifiedStatement>emptySet(),
Collections.<IdentifiedStatement>emptySet());
}
eliminateRedundantBreaks(switchStmt.getDefaultClause(), null,
Collections.<IdentifiedStatement>emptySet());
}
}
}
@Override
public void visit(SequentialStatement statement) {
List<Statement> statements = processSequence(statement.getSequence(), false);
if (statements.isEmpty()) {
resultStmt = null;
return;
}
if (statements.size() == 1) {
resultStmt = statements.get(0);
} else {
SequentialStatement result = new SequentialStatement();
result.getSequence().addAll(statements);
resultStmt = result;
statement.getSequence().clear();
statement.getSequence().addAll(statements);
resultStmt = statement;
}
}
@Override
public void visit(ConditionalStatement statement) {
statement.getCondition().acceptVisitor(this);
Expr predicate = resultExpr;
List<Statement> sequenceBackup = resultSequence;
resultSequence = new ArrayList<>();
statement.getConsequent().acceptVisitor(this);
Statement consequent = resultStmt;
Statement alternative = null;
if (statement.getAlternative() != null) {
statement.getAlternative().acceptVisitor(this);
alternative = resultStmt;
statement.setCondition(resultExpr);
List<Statement> consequent = processSequence(statement.getConsequent(), true);
List<Statement> alternative = processSequence(statement.getAlternative(), true);
if (consequent.isEmpty()) {
consequent.addAll(alternative);
alternative.clear();
statement.setCondition(ExprOptimizer.invert(statement.getCondition()));
}
if (consequent == null) {
if (alternative != null) {
Statement tmp = alternative;
alternative = consequent;
consequent = tmp;
predicate = ExprOptimizer.invert(predicate);
} else {
consequent = Statement.empty();
}
if (consequent.isEmpty()) {
resultStmt = Statement.empty();
return;
}
resultStmt = conditionalOptimizer.tryMakeInline(
(ConditionalStatement)Statement.cond(predicate, consequent, alternative));
resultSequence = sequenceBackup;
}
private void visitIdentified(IdentifiedStatement stmt, IdentifiedStatement copy) {
copies.put(stmt, copy);
statement.getConsequent().clear();
statement.getConsequent().addAll(consequent);
statement.getAlternative().clear();
statement.getAlternative().addAll(alternative);
resultStmt = statement;
}
@Override
public void visit(SwitchStatement statement) {
SwitchStatement result = new SwitchStatement();
result.setId(statement.getId());
visitIdentified(statement, result);
statement.getValue().acceptVisitor(this);
result.setValue(resultExpr);
statement.setValue(resultExpr);
for (SwitchClause clause : statement.getClauses()) {
clause.getStatement().acceptVisitor(this);
SwitchClause resultClause = new SwitchClause();
resultClause.setConditions(clause.getConditions());
resultClause.setStatement(resultStmt != null ? resultStmt : Statement.empty());
result.getClauses().add(resultClause);
List<Statement> newBody = processSequence(clause.getBody(), true);
clause.getBody().clear();
clause.getBody().addAll(newBody);
}
if (statement.getDefaultClause() != null) {
statement.getDefaultClause().acceptVisitor(this);
} else {
resultStmt = null;
}
result.setDefaultClause(resultStmt != null ? resultStmt : Statement.empty());
resultStmt = result;
List<Statement> newDefault = processSequence(statement.getDefaultClause(), true);
statement.getDefaultClause().clear();
statement.getDefaultClause().addAll(newDefault);
resultStmt = statement;
}
@Override
public void visit(WhileStatement statement) {
WhileStatement result = new WhileStatement();
result.setId(statement.getId());
visitIdentified(statement, result);
List<Statement> statements = processSequence(statement.getBody(), true);
statement.getBody().clear();
statement.getBody().addAll(statements);
if (statement.getCondition() != null) {
statement.getCondition().acceptVisitor(this);
result.setCondition(resultExpr);
} else {
result.setCondition(null);
statement.setCondition(resultExpr);
}
result.getBody().addAll(statements);
conditionalOptimizer.tryOptimize(result);
resultStmt = result;
resultStmt = statement;
}
@Override
public void visit(BlockStatement statement) {
BlockStatement result = new BlockStatement();
result.setId(statement.getId());
visitIdentified(statement, result);
List<Statement> statements = processSequence(statement.getBody(), false);
result.getBody().addAll(statements);
if (referencedStatements.containsKey(result)) {
resultStmt = conditionalOptimizer.tryOptimize(result);
eliminateRedundantBreaks(statements, Collections.<IdentifiedStatement>singleton(statement),
Collections.<IdentifiedStatement>emptySet());
if (referencedStatements.get(statement).equals(0)) {
SequentialStatement result = new SequentialStatement();
result.getSequence().addAll(statements);
resultStmt = result;
} else {
SequentialStatement altResult = new SequentialStatement();
altResult.getSequence().addAll(result.getBody());
resultStmt = altResult;
}
if (resultStmt instanceof BlockStatement) {
resultStmt = conditionalOptimizer.tryOptimizeElse((BlockStatement)resultStmt);
}
if (resultStmt instanceof BlockStatement) {
resultStmt = conditionalOptimizer.tryOptimizeSwitch((BlockStatement)resultStmt);
}
if (resultStmt instanceof ConditionalStatement) {
ConditionalStatement conditional = (ConditionalStatement)resultStmt;
conditional.getCondition().acceptVisitor(this);
conditional.setCondition(resultExpr);
statement.getBody().clear();
statement.getBody().addAll(statements);
resultStmt = statement;
}
}
@ -422,48 +472,28 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(BreakStatement statement) {
BreakStatement result = new BreakStatement();
if (statement.getTarget() != null) {
IdentifiedStatement targetCopy = copies.get(statement.getTarget());
result.setTarget(targetCopy);
Integer refCount = referencedStatements.get(targetCopy);
if (refCount == null) {
refCount = 0;
}
referencedStatements.put(targetCopy, refCount + 1);
}
resultStmt = result;
resultStmt = statement;
}
@Override
public void visit(ContinueStatement statement) {
ContinueStatement result = new ContinueStatement();
if (statement.getTarget() != null) {
IdentifiedStatement targetCopy = copies.get(statement.getTarget());
result.setTarget(targetCopy);
Integer refCount = referencedStatements.get(targetCopy);
if (refCount == null) {
refCount = 0;
}
referencedStatements.put(targetCopy, refCount + 1);
}
resultStmt = result;
resultStmt = statement;
}
@Override
public void visit(ReturnStatement statement) {
if (statement.getResult() == null) {
resultStmt = Statement.exitFunction(null);
} else {
if (statement.getResult() != null) {
statement.getResult().acceptVisitor(this);
resultStmt = Statement.exitFunction(resultExpr);
statement.setResult(resultExpr);
}
resultStmt = statement;
}
@Override
public void visit(ThrowStatement statement) {
statement.getException().acceptVisitor(this);
resultStmt = Statement.raiseException(resultExpr);
statement.setException(resultExpr);
resultStmt = statement;
}
@Override

View File

@ -42,18 +42,24 @@ class ReferenceCountingVisitor implements StatementVisitor {
@Override
public void visit(ConditionalStatement statement) {
statement.getConsequent().acceptVisitor(this);
if (statement.getAlternative() != null) {
statement.getAlternative().acceptVisitor(this);
for (Statement part : statement.getConsequent()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getAlternative()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(SwitchStatement statement) {
for (SwitchClause clause : statement.getClauses()) {
clause.getStatement().acceptVisitor(this);
for (Statement part : clause.getBody()) {
part.acceptVisitor(this);
}
}
for (Statement part : statement.getDefaultClause()) {
part.acceptVisitor(this);
}
statement.getDefaultClause().acceptVisitor(this);
}
@Override

View File

@ -388,10 +388,14 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.append("if").ws().append("(");
statement.getCondition().acceptVisitor(this);
writer.append(")").ws().append("{").softNewLine().indent();
statement.getConsequent().acceptVisitor(this);
if (statement.getAlternative() != null) {
for (Statement part : statement.getConsequent()) {
part.acceptVisitor(this);
}
if (!statement.getAlternative().isEmpty()) {
writer.outdent().append("}").ws().append("else").ws().append("{").indent().softNewLine();
statement.getAlternative().acceptVisitor(this);
for (Statement part : statement.getAlternative()) {
part.acceptVisitor(this);
}
}
writer.outdent().append("}").softNewLine();
} catch (IOException e) {
@ -413,12 +417,16 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.append("case ").append(condition).append(":").softNewLine();
}
writer.indent();
clause.getStatement().acceptVisitor(this);
for (Statement part : clause.getBody()) {
part.acceptVisitor(this);
}
writer.outdent();
}
if (statement.getDefaultClause() != null) {
writer.append("default:").softNewLine().indent();
statement.getDefaultClause().acceptVisitor(this);
for (Statement part : statement.getDefaultClause()) {
part.acceptVisitor(this);
}
writer.outdent();
}
writer.outdent().append("}").softNewLine();

View File

@ -413,10 +413,16 @@ class StatementGenerator implements InstructionVisitor {
conditions[i] = conditionList.get(i);
}
clause.setConditions(conditions);
clause.setStatement(generateJumpStatement(stmt, target));
Statement jumpStmt = generateJumpStatement(stmt, target);
if (jumpStmt != null) {
clause.getBody().add(jumpStmt);
}
stmt.getClauses().add(clause);
}
stmt.setDefaultClause(generateJumpStatement(insn.getDefaultTarget()));
Statement breakStmt = generateJumpStatement(insn.getDefaultTarget());
if (breakStmt != null) {
stmt.getDefaultClause().add(breakStmt);
}
statements.add(stmt);
}
@ -605,13 +611,9 @@ class StatementGenerator implements InstructionVisitor {
private void branch(Expr condition, BasicBlock consequentBlock, BasicBlock alternativeBlock) {
Statement consequent = generateJumpStatement(consequentBlock);
Statement alternative = generateJumpStatement(alternativeBlock);
if (consequent == null) {
consequent = Statement.empty();
}
if (alternative == null) {
alternative = Statement.empty();
}
statements.add(Statement.cond(condition, consequent, alternative));
statements.add(Statement.cond(condition,
consequent != null ? Arrays.asList(consequent) : Collections.<Statement>emptyList(),
alternative != null ? Arrays.asList(alternative) : Collections.<Statement>emptyList()));
}
private Expr compare(BinaryOperation op, Variable value) {

View File

@ -61,9 +61,11 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
@Override
public void visit(ConditionalStatement statement) {
statement.getCondition().acceptVisitor(this);
statement.getConsequent().acceptVisitor(this);
if (statement.getAlternative() != null) {
statement.getAlternative().acceptVisitor(this);
for (Statement part : statement.getConsequent()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getAlternative()) {
part.acceptVisitor(this);
}
}
@ -71,9 +73,13 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
public void visit(SwitchStatement statement) {
statement.getValue().acceptVisitor(this);
for (SwitchClause clause : statement.getClauses()) {
clause.getStatement().acceptVisitor(this);
for (Statement part : clause.getBody()) {
part.acceptVisitor(this);
}
}
for (Statement part : statement.getDefaultClause()) {
part.acceptVisitor(this);
}
statement.getDefaultClause().acceptVisitor(this);
}
@Override

View File

@ -15,14 +15,17 @@
*/
package org.teavm.javascript.ast;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class ConditionalStatement extends Statement {
private Expr condition;
private Statement consequent;
private Statement alternative;
private List<Statement> consequent = new ArrayList<>();
private List<Statement> alternative = new ArrayList<>();
public Expr getCondition() {
return condition;
@ -32,22 +35,14 @@ public class ConditionalStatement extends Statement {
this.condition = condition;
}
public Statement getConsequent() {
public List<Statement> getConsequent() {
return consequent;
}
public void setConsequent(Statement consequent) {
this.consequent = consequent;
}
public Statement getAlternative() {
public List<Statement> getAlternative() {
return alternative;
}
public void setAlternative(Statement alternative) {
this.alternative = alternative;
}
@Override
public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this);

View File

@ -119,9 +119,11 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(ConditionalStatement statement) {
statement.getCondition().acceptVisitor(this);
statement.getConsequent().acceptVisitor(this);
if (statement.getAlternative() != null) {
statement.getAlternative().acceptVisitor(this);
for (Statement part : statement.getConsequent()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getAlternative()) {
part.acceptVisitor(this);
}
}
@ -129,10 +131,12 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
public void visit(SwitchStatement statement) {
statement.getValue().acceptVisitor(this);
for (SwitchClause clause : statement.getClauses()) {
clause.getStatement().acceptVisitor(this);
for (Statement part : clause.getBody()) {
part.acceptVisitor(this);
}
}
if (statement.getDefaultClause() != null) {
statement.getDefaultClause().acceptVisitor(this);
for (Statement part : statement.getDefaultClause()) {
part.acceptVisitor(this);
}
}

View File

@ -15,6 +15,9 @@
*/
package org.teavm.javascript.ast;
import java.util.Collections;
import java.util.List;
/**
*
* @author Alexey Andreev
@ -52,16 +55,16 @@ public abstract class Statement {
return stmt;
}
public static Statement cond(Expr predicate, Statement consequent, Statement alternative) {
public static Statement cond(Expr predicate, List<Statement> consequent, List<Statement> alternative) {
ConditionalStatement statement = new ConditionalStatement();
statement.setCondition(predicate);
statement.setConsequent(consequent);
statement.setAlternative(alternative);
statement.getConsequent().addAll(consequent);
statement.getAlternative().addAll(alternative);
return statement;
}
public static Statement cond(Expr predicate, Statement consequent) {
return cond(predicate, consequent, null);
public static Statement cond(Expr predicate, List<Statement> consequent) {
return cond(predicate, consequent, Collections.<Statement>emptyList());
}
public static Statement initClass(String className) {

View File

@ -15,7 +15,9 @@
*/
package org.teavm.javascript.ast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
@ -23,7 +25,7 @@ import java.util.Arrays;
*/
public class SwitchClause {
private int[] conditions;
private Statement statement;
private List<Statement> body = new ArrayList<>();
public int[] getConditions() {
return conditions != null ? Arrays.copyOf(conditions, conditions.length) : null;
@ -33,11 +35,7 @@ public class SwitchClause {
this.conditions = conditions != null ? Arrays.copyOf(conditions, conditions.length) : null;
}
public Statement getStatement() {
return statement;
}
public void setStatement(Statement statement) {
this.statement = statement;
public List<Statement> getBody() {
return body;
}
}

View File

@ -25,20 +25,16 @@ import java.util.List;
public class SwitchStatement extends IdentifiedStatement {
private Expr value;
private List<SwitchClause> clauses = new ArrayList<>();
private Statement defaultClause;
private List<Statement> defaultClause = new ArrayList<>();
public List<SwitchClause> getClauses() {
return clauses;
}
public Statement getDefaultClause() {
public List<Statement> getDefaultClause() {
return defaultClause;
}
public void setDefaultClause(Statement defaultClause) {
this.defaultClause = defaultClause;
}
public Expr getValue() {
return value;
}