When removing empty if statements, extract expressions with side effects from its condition

This commit is contained in:
Alexey Andreev 2016-06-18 19:55:46 +03:00 committed by Alexey Andreev
parent 19625034c4
commit ea9605e518
5 changed files with 137 additions and 10 deletions

View File

@ -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<Statement> target;
public ExpressionSideEffectDecomposer(List<Statement> 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);
}
}

View File

@ -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();

View File

@ -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("<init>")) {
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<Incoming> 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<Instruction> instructions = block.getInstructions();
for (int j = instructions.size() - 1; j >= 0; --j) {
Instruction insn = instructions.get(j);

View File

@ -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();
}
}

View File

@ -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);