From 8be9e6c4bad777f976d6cf440d6cb306a30fa915 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sat, 14 Mar 2015 23:45:01 +0300 Subject: [PATCH] First attempt to make AST optimizer faster --- ...untVisitor.java => BlockCountVisitor.java} | 4 +- .../javascript/EscapingStatementFinder.java | 130 ++++++++++++++++++ .../teavm/javascript/OptimizingVisitor.java | 52 ++++++- 3 files changed, 179 insertions(+), 7 deletions(-) rename teavm-core/src/main/java/org/teavm/javascript/{CertainBlockCountVisitor.java => BlockCountVisitor.java} (95%) create mode 100644 teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java diff --git a/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/BlockCountVisitor.java similarity index 95% rename from teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java rename to teavm-core/src/main/java/org/teavm/javascript/BlockCountVisitor.java index 11702da38..39354bcbf 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/BlockCountVisitor.java @@ -22,11 +22,11 @@ import org.teavm.javascript.ast.*; * * @author Alexey Andreev */ -class CertainBlockCountVisitor implements StatementVisitor { +class BlockCountVisitor implements StatementVisitor { private BlockStatement blockToCount; private int count; - public CertainBlockCountVisitor(BlockStatement blockToCount) { + public BlockCountVisitor(BlockStatement blockToCount) { this.blockToCount = blockToCount; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java b/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java new file mode 100644 index 000000000..370a56d8f --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/javascript/EscapingStatementFinder.java @@ -0,0 +1,130 @@ +/* + * 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.List; +import java.util.Set; +import org.teavm.javascript.ast.*; + +/** + * + * @author Alexey Andreev + */ +class EscapingStatementFinder implements StatementVisitor{ + public boolean escaping; + private Set outerStatements; + + public EscapingStatementFinder(Set nestingStatements) { + this.outerStatements = nestingStatements; + } + + public boolean check(List statements) { + if (!escaping) { + if (statements.isEmpty()) { + escaping = true; + } else { + statements.get(statements.size() - 1).acceptVisitor(this); + } + } + return escaping; + } + + @Override + public void visit(AssignmentStatement statement) { + escaping = true; + } + + @Override + public void visit(SequentialStatement statement) { + check(statement.getSequence()); + } + + @Override + public void visit(ConditionalStatement statement) { + if (!check(statement.getConsequent())) { + check(statement.getAlternative()); + } + } + + @Override + public void visit(SwitchStatement statement) { + outerStatements.add(statement); + for (SwitchClause clause : statement.getClauses()) { + if (check(clause.getBody())) { + break; + } + } + check(statement.getDefaultClause()); + outerStatements.remove(statement); + } + + @Override + public void visit(WhileStatement statement) { + outerStatements.add(statement); + check(statement.getBody()); + outerStatements.remove(statement); + } + + @Override + public void visit(BlockStatement statement) { + outerStatements.add(statement); + check(statement.getBody()); + outerStatements.remove(statement); + } + + @Override + public void visit(BreakStatement statement) { + escaping = !outerStatements.contains(statement.getTarget()); + } + + @Override + public void visit(ContinueStatement statement) { + escaping = !outerStatements.contains(statement.getTarget()); + } + + @Override + public void visit(ReturnStatement statement) { + } + + @Override + public void visit(ThrowStatement statement) { + } + + @Override + public void visit(InitClassStatement statement) { + escaping = true; + } + + @Override + public void visit(TryCatchStatement statement) { + check(statement.getProtectedBody()); + check(statement.getHandler()); + } + + @Override + public void visit(GotoPartStatement statement) { + } + + @Override + public void visit(MonitorEnterStatement statement) { + escaping = true; + } + + @Override + public void visit(MonitorExitStatement statement) { + escaping = true; + } +} 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 c0923f820..d62acc07a 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -28,6 +28,8 @@ 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; @@ -370,15 +372,29 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { return; } Statement last = statements.get(statements.size() - 1); - if (last instanceof BreakStatement && exit != null) { - IdentifiedStatement target = ((BreakStatement)last).getTarget(); - if (exit == target) { - statements.remove(statements.size() - 1); + if (last instanceof BreakStatement) { + BreakStatement breakStmt = (BreakStatement)last; + if (exit != null) { + IdentifiedStatement target = breakStmt.getTarget(); + 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) { @@ -436,20 +452,39 @@ 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()) { @@ -495,6 +530,7 @@ 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()) { @@ -506,10 +542,12 @@ 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); @@ -558,13 +596,16 @@ 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); - CertainBlockCountVisitor usageCounter = new CertainBlockCountVisitor(statement); + statements = processSequence(statements); + BlockCountVisitor usageCounter = new BlockCountVisitor(statement); usageCounter.visit(statements); if (usageCounter.getCount() == 0) { SequentialStatement result = new SequentialStatement(); @@ -575,6 +616,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { statement.getBody().addAll(statements); resultStmt = statement; } + outerStatements.remove(statement); } @Override