diff --git a/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java new file mode 100644 index 000000000..1373f6be1 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java @@ -0,0 +1,156 @@ +/* + * Copyright 2015 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.*; +import org.teavm.javascript.ast.*; + +/** + * + * @author Alexey Andreev + */ +class BreakEliminator implements StatementVisitor { + private Map> blockSuccessors = new HashMap<>(); + private Set outerStatements = new HashSet<>(); + private List currentSequence; + private boolean sequenceEscapes; + private int currentIndex; + + private void processSequence(List statements) { + List oldSequence = currentSequence; + int oldIndex = currentIndex; + boolean oldEscapes = sequenceEscapes; + + sequenceEscapes = escapes(statements); + currentSequence = statements; + for (currentIndex = 0; currentIndex < currentSequence.size(); ++currentIndex) { + statements.get(currentIndex).acceptVisitor(this); + } + + sequenceEscapes = oldEscapes; + currentIndex = oldIndex; + currentSequence = oldSequence; + } + + @Override + public void visit(AssignmentStatement statement) { + } + + @Override + public void visit(SequentialStatement statement) { + if (currentSequence == null) { + processSequence(statement.getSequence()); + return; + } + --currentIndex; + currentSequence.remove(currentIndex); + currentSequence.addAll(currentIndex, statement.getSequence()); + } + + @Override + public void visit(ConditionalStatement statement) { + processSequence(statement.getConsequent()); + processSequence(statement.getAlternative()); + } + + @Override + public void visit(SwitchStatement statement) { + outerStatements.add(statement); + for (SwitchClause clause : statement.getClauses()) { + processSequence(clause.getBody()); + } + processSequence(statement.getDefaultClause()); + outerStatements.remove(statement); + } + + @Override + public void visit(WhileStatement statement) { + outerStatements.add(statement); + processSequence(statement.getBody()); + outerStatements.remove(statement); + } + + @Override + public void visit(BlockStatement statement) { + outerStatements.add(statement); + if (!sequenceEscapes && !escapes(statement.getBody())) { + blockSuccessors.put(statement, currentSequence.subList(currentIndex + 1, currentSequence.size())); + } + processSequence(statement.getBody()); + blockSuccessors.remove(statement); + outerStatements.remove(statement); + } + + @Override + public void visit(BreakStatement statement) { + if (blockSuccessors.containsKey(statement.getTarget())) { + BlockCountVisitor usageCounter = new BlockCountVisitor( + (BlockStatement)statement.getTarget()); + statement.getTarget().acceptVisitor(usageCounter); + if (usageCounter.getCount() == 1) { + currentSequence.subList(currentIndex, currentSequence.size()).clear(); + List successors = blockSuccessors.remove(statement.getTarget()); + currentSequence.addAll(successors); + successors.clear(); + --currentIndex; + sequenceEscapes = escapes(currentSequence); + return; + } + } + currentSequence.subList(currentIndex + 1, currentSequence.size()).clear(); + } + + @Override + public void visit(ContinueStatement statement) { + currentSequence.subList(currentIndex + 1, currentSequence.size()).clear(); + } + + @Override + public void visit(ReturnStatement statement) { + currentSequence.subList(currentIndex + 1, currentSequence.size()).clear(); + } + + @Override + public void visit(ThrowStatement statement) { + currentSequence.subList(currentIndex + 1, currentSequence.size()).clear(); + } + + @Override + public void visit(InitClassStatement statement) { + } + + @Override + public void visit(TryCatchStatement statement) { + processSequence(statement.getProtectedBody()); + processSequence(statement.getHandler()); + } + + @Override + public void visit(GotoPartStatement statement) { + } + + @Override + public void visit(MonitorEnterStatement statement) { + } + + @Override + public void visit(MonitorExitStatement statement) { + } + + private boolean escapes(List statements) { + return new EscapingStatementFinder(outerStatements).check(statements); + } +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java b/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java index 370a56d8f..79017d0b3 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java @@ -73,9 +73,7 @@ class EscapingStatementFinder implements StatementVisitor{ @Override public void visit(WhileStatement statement) { - outerStatements.add(statement); - check(statement.getBody()); - outerStatements.remove(statement); + escaping = true; } @Override 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 fce043a1f..34bbccb0c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java @@ -35,6 +35,8 @@ public class Optimizer { preservedVars[i] = true; } } + BreakEliminator breakEliminator = new BreakEliminator(); + method.getBody().acceptVisitor(breakEliminator); OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.reads); method.getBody().acceptVisitor(optimizer); method.setBody(optimizer.resultStmt); @@ -64,6 +66,8 @@ public class Optimizer { } for (int i = 0; i < splitter.size(); ++i) { AsyncMethodPart part = method.getBody().get(i); + BreakEliminator breakEliminator = new BreakEliminator(); + part.getStatement().acceptVisitor(breakEliminator); OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, readFrequencies[i]); part.getStatement().acceptVisitor(optimizer); part.setStatement(optimizer.resultStmt); 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 d62acc07a..a18740845 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -28,8 +28,6 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { private boolean[] preservedVars; private int[] readFrequencies; private List resultSequence; - private Map> blockSuccessors = new HashMap<>(); - private Set outerStatements = new HashSet<>(); public OptimizingVisitor(boolean[] preservedVars, int[] readFreqencies) { this.preservedVars = preservedVars; @@ -379,22 +377,11 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { if (exit == target) { statements.remove(statements.size() - 1); } - } else if (blockSuccessors.containsKey(breakStmt.getTarget())) { - BlockCountVisitor usageCounter = new BlockCountVisitor( - (BlockStatement)breakStmt.getTarget()); - breakStmt.getTarget().acceptVisitor(usageCounter); - if (usageCounter.getCount() == 1) { - statements.remove(statements.size() - 1); - List successors = blockSuccessors.remove(breakStmt.getTarget()); - statements.addAll(successors); - successors.clear(); - } } } if (statements.isEmpty()) { return; } - boolean escapes = escapes(statements); for (int i = 0; i < statements.size(); ++i) { Statement stmt = statements.get(i); if (stmt instanceof ConditionalStatement) { @@ -417,7 +404,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { if (last instanceof BreakStatement) { BreakStatement breakStmt = (BreakStatement)last; if (exit != null && exit == breakStmt.getTarget()) { - cond.getAlternative().remove(cond.getConsequent().size() - 1); + cond.getAlternative().remove(cond.getAlternative().size() - 1); List remaining = statements.subList(i + 1, statements.size()); cond.getConsequent().addAll(remaining); remaining.clear(); @@ -452,40 +439,20 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { } } else if (stmt instanceof BlockStatement) { BlockStatement nestedBlock = (BlockStatement)stmt; - outerStatements.add(nestedBlock); - if (!escapes && !escapes(nestedBlock.getBody())) { - blockSuccessors.put(nestedBlock, statements.subList(i + 1, statements.size())); - } eliminateRedundantBreaks(nestedBlock.getBody(), nestedBlock); - blockSuccessors.remove(nestedBlock); - outerStatements.remove(nestedBlock); } else if (stmt instanceof WhileStatement) { WhileStatement whileStmt = (WhileStatement)stmt; - outerStatements.add(whileStmt); eliminateRedundantBreaks(whileStmt.getBody(), null); - outerStatements.remove(whileStmt); } else if (stmt instanceof SwitchStatement) { SwitchStatement switchStmt = (SwitchStatement)stmt; - outerStatements.add(switchStmt); - if (i == statements.size() - 1) { - for (SwitchClause clause : switchStmt.getClauses()) { - eliminateRedundantBreaks(clause.getBody(), exit); - } - eliminateRedundantBreaks(switchStmt.getDefaultClause(), exit); - } for (SwitchClause clause : switchStmt.getClauses()) { eliminateRedundantBreaks(clause.getBody(), null); } eliminateRedundantBreaks(switchStmt.getDefaultClause(), null); - outerStatements.remove(switchStmt); } } } - private boolean escapes(List statements) { - return new EscapingStatementFinder(outerStatements).check(statements); - } - private void normalizeConditional(ConditionalStatement stmt) { if (stmt.getConsequent().isEmpty()) { stmt.getConsequent().addAll(stmt.getAlternative()); @@ -530,7 +497,6 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(SwitchStatement statement) { - outerStatements.add(statement); statement.getValue().acceptVisitor(this); statement.setValue(resultExpr); for (SwitchClause clause : statement.getClauses()) { @@ -542,12 +508,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { statement.getDefaultClause().clear(); statement.getDefaultClause().addAll(newDefault); resultStmt = statement; - outerStatements.remove(statement); } @Override public void visit(WhileStatement statement) { - outerStatements.add(statement); if (statement.getBody().size() == 1 && statement.getBody().get(0) instanceof WhileStatement) { WhileStatement innerLoop = (WhileStatement)statement.getBody().get(0); BreakToContinueReplacer replacer = new BreakToContinueReplacer(innerLoop, statement); @@ -596,12 +560,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { break; } resultStmt = statement; - outerStatements.remove(statements); } @Override public void visit(BlockStatement statement) { - outerStatements.add(statement); List statements = processSequence(statement.getBody()); eliminateRedundantBreaks(statements, statement); statements = processSequence(statements); @@ -616,7 +578,6 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { statement.getBody().addAll(statements); resultStmt = statement; } - outerStatements.remove(statement); } @Override