diff --git a/teavm-classlib/pom.xml b/teavm-classlib/pom.xml
index 76ebea08d..9f638f16a 100644
--- a/teavm-classlib/pom.xml
+++ b/teavm-classlib/pom.xml
@@ -53,7 +53,7 @@
process-test-classes
false
- 0
+ 1
diff --git a/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java
new file mode 100644
index 000000000..384d9a1d8
--- /dev/null
+++ b/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java
@@ -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 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) {
+ }
+}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ConditionalOptimizer.java b/teavm-core/src/main/java/org/teavm/javascript/ConditionalOptimizer.java
deleted file mode 100644
index 24414af64..000000000
--- a/teavm-core/src/main/java/org/teavm/javascript/ConditionalOptimizer.java
+++ /dev/null
@@ -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 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 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;
- }
-}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java
index 1215f0c65..ea374db8f 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java
@@ -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();
diff --git a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java
index d26635b05..32606d30d 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java
@@ -26,15 +26,11 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public Expr resultExpr;
public Statement resultStmt;
private ReadWriteStatsBuilder stats;
- private Map copies = new HashMap<>();
- private Map referencedStatements = new HashMap<>();
- private ConditionalOptimizer conditionalOptimizer = new ConditionalOptimizer();
+ Map referencedStatements = new HashMap<>();
private List 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 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 statements, Set currentExits,
+ Set 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 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 remaining = statements.subList(i + 1, statements.size());
+ cond.getAlternative().addAll(remaining);
+ remaining.clear();
+ visit(cond);
+ if (resultStmt == cond) {
+ eliminateRedundantBreaks(cond.getConsequent(),
+ Collections.emptySet(), nestedExits);
+ eliminateRedundantBreaks(cond.getAlternative(),
+ Collections.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 remaining = statements.subList(i + 1, statements.size());
+ cond.getConsequent().addAll(remaining);
+ remaining.clear();
+ visit(cond);
+ if (resultStmt == cond) {
+ eliminateRedundantBreaks(cond.getConsequent(),
+ Collections.emptySet(), nestedExits);
+ eliminateRedundantBreaks(cond.getAlternative(),
+ Collections.emptySet(), nestedExits);
+ }
+ statements.set(i, resultStmt);
+ break;
+ }
+ }
+ } else if (stmt instanceof BlockStatement) {
+ BlockStatement nestedBlock = (BlockStatement)stmt;
+ eliminateRedundantBreaks(nestedBlock.getBody(),
+ Collections.singleton(nestedBlock), nestedExits);
+ } else if (stmt instanceof WhileStatement) {
+ WhileStatement whileStmt = (WhileStatement)stmt;
+ eliminateRedundantBreaks(whileStmt.getBody(), Collections.emptySet(),
+ Collections.emptySet());
+ } else if (stmt instanceof SwitchStatement) {
+ SwitchStatement switchStmt = (SwitchStatement)stmt;
+ for (SwitchClause clause : switchStmt.getClauses()) {
+ eliminateRedundantBreaks(clause.getBody(), Collections.emptySet(),
+ Collections.emptySet());
+ }
+ eliminateRedundantBreaks(switchStmt.getDefaultClause(), null,
+ Collections.emptySet());
+ }
+ }
+ }
+
@Override
public void visit(SequentialStatement statement) {
List 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 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 consequent = processSequence(statement.getConsequent(), true);
+ List 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 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 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 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 statements = processSequence(statement.getBody(), false);
- result.getBody().addAll(statements);
- if (referencedStatements.containsKey(result)) {
- resultStmt = conditionalOptimizer.tryOptimize(result);
+ eliminateRedundantBreaks(statements, Collections.singleton(statement),
+ Collections.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
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java
index ff1493e36..ff6dcde4e 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java
@@ -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
diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java
index 706b2f984..cd1774b84 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java
@@ -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();
diff --git a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java
index aa25c490a..316d51d90 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java
@@ -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.emptyList(),
+ alternative != null ? Arrays.asList(alternative) : Collections.emptyList()));
}
private Expr compare(BinaryOperation op, Variable value) {
diff --git a/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java
index ac9a4fd22..d61066b21 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java
@@ -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
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/ConditionalStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/ConditionalStatement.java
index 9e16224c7..c2fee2ffa 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ast/ConditionalStatement.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ast/ConditionalStatement.java
@@ -1,12 +1,12 @@
/*
* Copyright 2011 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.
@@ -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 consequent = new ArrayList<>();
+ private List 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 getConsequent() {
return consequent;
}
- public void setConsequent(Statement consequent) {
- this.consequent = consequent;
- }
-
- public Statement getAlternative() {
+ public List getAlternative() {
return alternative;
}
- public void setAlternative(Statement alternative) {
- this.alternative = alternative;
- }
-
@Override
public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this);
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java
index 0ddb850f5..01779e0f2 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java
@@ -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);
}
}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/Statement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/Statement.java
index 6175254cd..0a2219f63 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ast/Statement.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ast/Statement.java
@@ -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 consequent, List 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 consequent) {
+ return cond(predicate, consequent, Collections.emptyList());
}
public static Statement initClass(String className) {
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchClause.java b/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchClause.java
index db82197db..bbdf1da4b 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchClause.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchClause.java
@@ -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 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 getBody() {
+ return body;
}
}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchStatement.java
index 4b48f8e0f..63eec964f 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchStatement.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ast/SwitchStatement.java
@@ -25,20 +25,16 @@ import java.util.List;
public class SwitchStatement extends IdentifiedStatement {
private Expr value;
private List clauses = new ArrayList<>();
- private Statement defaultClause;
+ private List defaultClause = new ArrayList<>();
public List getClauses() {
return clauses;
}
- public Statement getDefaultClause() {
+ public List getDefaultClause() {
return defaultClause;
}
- public void setDefaultClause(Statement defaultClause) {
- this.defaultClause = defaultClause;
- }
-
public Expr getValue() {
return value;
}