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; }