diff --git a/teavm-core/src/main/java/org/teavm/javascript/AllBlocksCountVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/AllBlocksCountVisitor.java new file mode 100644 index 000000000..7f0d0fd0e --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/javascript/AllBlocksCountVisitor.java @@ -0,0 +1,134 @@ +/* + * 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.HashMap; +import java.util.List; +import java.util.Map; +import org.teavm.javascript.ast.*; + +/** + * + * @author Alexey Andreev + */ +class AllBlocksCountVisitor implements StatementVisitor { + private Map blocksCount = new HashMap<>(); + private IdentifiedStatement currentBlock; + + public void visit(List statements) { + if (statements == null) { + return; + } + for (Statement part : statements) { + part.acceptVisitor(this); + } + } + + public int getCount(IdentifiedStatement statement) { + Integer result = blocksCount.get(statement); + return result != null ? result : 0; + } + + @Override + public void visit(AssignmentStatement statement) { + } + + @Override + public void visit(SequentialStatement statement) { + visit(statement.getSequence()); + } + + @Override + public void visit(ConditionalStatement statement) { + visit(statement.getConsequent()); + visit(statement.getAlternative()); + } + + @Override + public void visit(SwitchStatement statement) { + IdentifiedStatement oldCurrentBlock = currentBlock; + currentBlock = statement; + for (SwitchClause clause : statement.getClauses()) { + visit(clause.getBody()); + } + visit(statement.getDefaultClause()); + currentBlock = oldCurrentBlock; + } + + @Override + public void visit(WhileStatement statement) { + IdentifiedStatement oldCurrentBlock = currentBlock; + currentBlock = statement; + visit(statement.getBody()); + currentBlock = oldCurrentBlock; + } + + @Override + public void visit(BlockStatement statement) { + IdentifiedStatement oldCurrentBlock = currentBlock; + currentBlock = statement; + visit(statement.getBody()); + currentBlock = oldCurrentBlock; + } + + @Override + public void visit(BreakStatement statement) { + IdentifiedStatement target = statement.getTarget(); + if (target == null) { + target = currentBlock; + } + blocksCount.put(target, getCount(target) + 1); + } + + @Override + public void visit(ContinueStatement statement) { + IdentifiedStatement target = statement.getTarget(); + if (target == null) { + target = currentBlock; + } + blocksCount.put(target, getCount(target) + 1); + } + + @Override + public void visit(ReturnStatement statement) { + } + + @Override + public void visit(ThrowStatement statement) { + } + + @Override + public void visit(InitClassStatement statement) { + } + + @Override + public void visit(TryCatchStatement statement) { + visit(statement.getProtectedBody()); + visit(statement.getHandler()); + } + + @Override + public void visit(GotoPartStatement statement) { + } + + @Override + public void visit(MonitorEnterStatement statement) { + } + + @Override + public void visit(MonitorExitStatement statement) { + } +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java index 1373f6be1..94bb2ef74 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/BreakEliminator.java @@ -28,6 +28,13 @@ class BreakEliminator implements StatementVisitor { private List currentSequence; private boolean sequenceEscapes; private int currentIndex; + private AllBlocksCountVisitor usageCounter; + + public void eliminate(Statement statement) { + usageCounter = new AllBlocksCountVisitor(); + statement.acceptVisitor(usageCounter); + statement.acceptVisitor(this); + } private void processSequence(List statements) { List oldSequence = currentSequence; @@ -97,10 +104,7 @@ class BreakEliminator implements StatementVisitor { @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) { + if (usageCounter.getCount(statement.getTarget()) == 1) { currentSequence.subList(currentIndex, currentSequence.size()).clear(); List successors = blockSuccessors.remove(statement.getTarget()); currentSequence.addAll(successors); 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 34bbccb0c..c57a126f7 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java @@ -36,7 +36,7 @@ public class Optimizer { } } BreakEliminator breakEliminator = new BreakEliminator(); - method.getBody().acceptVisitor(breakEliminator); + breakEliminator.eliminate(method.getBody()); OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.reads); method.getBody().acceptVisitor(optimizer); method.setBody(optimizer.resultStmt); @@ -67,7 +67,7 @@ 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); + breakEliminator.eliminate(part.getStatement()); 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 a18740845..036630fe5 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -370,13 +370,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { return; } Statement last = statements.get(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); - } + if (last instanceof BreakStatement && exit != null) { + IdentifiedStatement target = ((BreakStatement)last).getTarget(); + if (exit == target) { + statements.remove(statements.size() - 1); } } if (statements.isEmpty()) { @@ -453,6 +450,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { } } + private void normalizeConditional(ConditionalStatement stmt) { if (stmt.getConsequent().isEmpty()) { stmt.getConsequent().addAll(stmt.getAlternative()); @@ -566,7 +564,6 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { public void visit(BlockStatement statement) { List statements = processSequence(statement.getBody()); eliminateRedundantBreaks(statements, statement); - statements = processSequence(statements); BlockCountVisitor usageCounter = new BlockCountVisitor(statement); usageCounter.visit(statements); if (usageCounter.getCount() == 0) { diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java index 0c6fdf36c..413421a0c 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -292,7 +292,7 @@ public class TeaVMTool { } targetDirectory.mkdirs(); try (Writer writer = new OutputStreamWriter(new BufferedOutputStream( - new FileOutputStream(new File(targetDirectory, targetFileName))), "UTF-8")) { + new FileOutputStream(new File(targetDirectory, targetFileName)), 65536), "UTF-8")) { if (runtime == RuntimeCopyOperation.MERGED) { vm.add(runtimeInjector); }