diff --git a/core/src/main/java/org/teavm/javascript/ExpressionSideEffectDecomposer.java b/core/src/main/java/org/teavm/javascript/ExpressionSideEffectDecomposer.java new file mode 100644 index 000000000..5ed8c2061 --- /dev/null +++ b/core/src/main/java/org/teavm/javascript/ExpressionSideEffectDecomposer.java @@ -0,0 +1,116 @@ +/* + * Copyright 2016 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 org.teavm.javascript.ast.BinaryExpr; +import org.teavm.javascript.ast.ConditionalExpr; +import org.teavm.javascript.ast.ConditionalStatement; +import org.teavm.javascript.ast.ConstantExpr; +import org.teavm.javascript.ast.Expr; +import org.teavm.javascript.ast.ExprVisitor; +import org.teavm.javascript.ast.InstanceOfExpr; +import org.teavm.javascript.ast.InvocationExpr; +import org.teavm.javascript.ast.NewArrayExpr; +import org.teavm.javascript.ast.NewExpr; +import org.teavm.javascript.ast.NewMultiArrayExpr; +import org.teavm.javascript.ast.QualificationExpr; +import org.teavm.javascript.ast.Statement; +import org.teavm.javascript.ast.SubscriptExpr; +import org.teavm.javascript.ast.UnaryExpr; +import org.teavm.javascript.ast.UnwrapArrayExpr; +import org.teavm.javascript.ast.VariableExpr; + +public class ExpressionSideEffectDecomposer implements ExprVisitor { + private List target; + + public ExpressionSideEffectDecomposer(List target) { + this.target = target; + } + + @Override + public void visit(BinaryExpr expr) { + expr.getFirstOperand().acceptVisitor(this); + expr.getSecondOperand().acceptVisitor(this); + } + + @Override + public void visit(UnaryExpr expr) { + expr.getOperand().acceptVisitor(this); + } + + @Override + public void visit(ConditionalExpr expr) { + ConditionalStatement statement = new ConditionalStatement(); + statement.setCondition(expr.getCondition()); + expr.getCondition().acceptVisitor(new ExpressionSideEffectDecomposer(statement.getConsequent())); + expr.getAlternative().acceptVisitor(new ExpressionSideEffectDecomposer(statement.getAlternative())); + target.add(statement); + } + + @Override + public void visit(ConstantExpr expr) { + } + + @Override + public void visit(VariableExpr expr) { + } + + @Override + public void visit(SubscriptExpr expr) { + expr.getArray().acceptVisitor(this); + expr.getIndex().acceptVisitor(this); + } + + @Override + public void visit(UnwrapArrayExpr expr) { + expr.getArray().acceptVisitor(this); + } + + @Override + public void visit(InvocationExpr expr) { + target.add(Statement.assign(null, expr)); + } + + @Override + public void visit(QualificationExpr expr) { + if (expr.getQualified() != null) { + expr.getQualified().acceptVisitor(this); + } + } + + @Override + public void visit(NewExpr expr) { + target.add(Statement.assign(null, expr)); + } + + @Override + public void visit(NewArrayExpr expr) { + expr.getLength().acceptVisitor(this); + } + + @Override + public void visit(NewMultiArrayExpr expr) { + for (Expr dimension : expr.getDimensions()) { + dimension.acceptVisitor(this); + } + } + + @Override + public void visit(InstanceOfExpr expr) { + expr.getExpr().acceptVisitor(this); + } +} diff --git a/core/src/main/java/org/teavm/javascript/OptimizingVisitor.java b/core/src/main/java/org/teavm/javascript/OptimizingVisitor.java index 45b5f4532..814ff9d06 100644 --- a/core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -505,7 +505,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { statement.setCondition(ExprOptimizer.invert(statement.getCondition())); } if (consequent.isEmpty()) { - resultStmt = Statement.empty(); + SequentialStatement sequentialStatement = new SequentialStatement(); + resultStmt = sequentialStatement; + statement.getCondition().acceptVisitor(new ExpressionSideEffectDecomposer( + sequentialStatement.getSequence())); return; } statement.getConsequent().clear(); diff --git a/core/src/main/java/org/teavm/optimization/Inlining.java b/core/src/main/java/org/teavm/optimization/Inlining.java index 7cf30908f..0360ebb93 100644 --- a/core/src/main/java/org/teavm/optimization/Inlining.java +++ b/core/src/main/java/org/teavm/optimization/Inlining.java @@ -84,15 +84,15 @@ public class Inlining { splitBlock.getInstructions().addAll(instructionsToMove); copyTryCatchBlocks(block, splitBlock); - JumpInstruction jumpToInlinedProgram = new JumpInstruction(); - jumpToInlinedProgram.setTarget(firstInlineBlock); - block.getInstructions().set(planEntry.targetInstruction, jumpToInlinedProgram); - + block.getInstructions().remove(block.getInstructions().size() - 1); if (invoke.getInstance() == null || invoke.getMethod().getName().equals("")) { InitClassInstruction clinit = new InitClassInstruction(); clinit.setClassName(invoke.getMethod().getClassName()); - firstInlineBlock.getInstructions().add(clinit); + block.getInstructions().add(clinit); } + JumpInstruction jumpToInlinedProgram = new JumpInstruction(); + jumpToInlinedProgram.setTarget(firstInlineBlock); + block.getInstructions().add(jumpToInlinedProgram); for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) { BasicBlock blockToInline = inlineProgram.basicBlockAt(i); @@ -214,12 +214,13 @@ public class Inlining { tryCatchCopy.setExceptionVariable(source.getProgram().createVariable()); List handlerIncomings = tryCatch.getHandler().getPhis().stream() .flatMap(phi -> phi.getIncomings().stream()) - .filter(incoming -> incoming.getValue() == tryCatch.getExceptionVariable()) + .filter(incoming -> incoming.getValue() == tryCatch.getExceptionVariable() + && incoming.getSource() == source) .collect(Collectors.toList()); for (Incoming incoming : handlerIncomings) { Incoming incomingCopy = new Incoming(); incomingCopy.setValue(tryCatchCopy.getExceptionVariable()); - incomingCopy.setSource(incoming.getSource()); + incomingCopy.setSource(target); incoming.getPhi().getIncomings().add(incomingCopy); } copiedTryCatches.add(tryCatchCopy); @@ -236,6 +237,9 @@ public class Inlining { for (int i = program.basicBlockCount() - 1; i >= 0; --i) { BasicBlock block = program.basicBlockAt(i); + if (!block.getTryCatchBlocks().isEmpty()) { + continue; + } List instructions = block.getInstructions(); for (int j = instructions.size() - 1; j >= 0; --j) { Instruction insn = instructions.get(j); diff --git a/core/src/main/java/org/teavm/optimization/LoopInversion.java b/core/src/main/java/org/teavm/optimization/LoopInversion.java index 6ebd14bff..5b9d93fd1 100644 --- a/core/src/main/java/org/teavm/optimization/LoopInversion.java +++ b/core/src/main/java/org/teavm/optimization/LoopInversion.java @@ -21,6 +21,6 @@ import org.teavm.model.Program; public class LoopInversion implements MethodOptimization { @Override public boolean optimize(MethodReader method, Program program) { - return new LoopInversionImpl(program, method.parameterCount() + 1).apply(); + return new LoopInversionImpl(method, program, method.parameterCount() + 1).apply(); } } diff --git a/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java b/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java index e89030dc1..67e39dbca 100644 --- a/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java +++ b/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java @@ -35,6 +35,7 @@ import org.teavm.common.LoopGraph; import org.teavm.model.BasicBlock; import org.teavm.model.Incoming; import org.teavm.model.Instruction; +import org.teavm.model.MethodReader; import org.teavm.model.Phi; import org.teavm.model.Program; import org.teavm.model.TryCatchBlock; @@ -78,6 +79,7 @@ import org.teavm.model.util.UsageExtractor; * all remaining nodes are *condition*. */ class LoopInversionImpl { + private final MethodReader method; private final Program program; private final int parameterCount; private Graph cfg; @@ -87,7 +89,8 @@ class LoopInversionImpl { private BasicBlock[] definitionPlaces; private boolean affected; - LoopInversionImpl(Program program, int parameterCount) { + LoopInversionImpl(MethodReader method, Program program, int parameterCount) { + this.method = method; this.program = program; this.parameterCount = parameterCount; definitionPlaces = ProgramUtils.getVariableDefinitionPlaces(program); @@ -112,6 +115,7 @@ class LoopInversionImpl { inputs[i] = program.variableAt(i); } new PhiUpdater().updatePhis(program, inputs); + new UnusedVariableElimination().optimize(method, program); } } } while (postponed);