mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
Adds JavaScript AST optimizer.
This commit is contained in:
parent
3445910866
commit
4e4d0cfe9e
|
@ -16,6 +16,10 @@ public class SourceWriter {
|
|||
this.naming = naming;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
sb.setLength(0);
|
||||
}
|
||||
|
||||
public SourceWriter append(String value) {
|
||||
appendIndent();
|
||||
sb.append(value);
|
||||
|
@ -34,6 +38,12 @@ public class SourceWriter {
|
|||
return this;
|
||||
}
|
||||
|
||||
public SourceWriter append(char value) {
|
||||
appendIndent();
|
||||
sb.append(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceWriter appendClass(String cls) {
|
||||
appendIndent();
|
||||
sb.append(naming.getNameFor(cls));
|
||||
|
@ -69,7 +79,6 @@ public class SourceWriter {
|
|||
|
||||
public SourceWriter indent() {
|
||||
++indentSize;
|
||||
newLine();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,19 +12,23 @@ import java.util.List;
|
|||
public class GraphBuilder {
|
||||
private GraphImpl builtGraph;
|
||||
private List<IntegerArray> addedEdges = new ArrayList<>();
|
||||
private int sz = 0;
|
||||
|
||||
public GraphBuilder() {
|
||||
}
|
||||
|
||||
public GraphBuilder(int sz) {
|
||||
addedEdges.addAll(Collections.<IntegerArray>nCopies(sz, null));
|
||||
this.sz = sz;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
addedEdges.clear();
|
||||
sz = 0;
|
||||
}
|
||||
|
||||
public void addEdge(int from, int to) {
|
||||
sz = Math.max(sz, Math.max(from, to) + 1);
|
||||
builtGraph = null;
|
||||
if (addedEdges.size() == from) {
|
||||
addedEdges.add(IntegerArray.of(to));
|
||||
|
@ -43,11 +47,11 @@ public class GraphBuilder {
|
|||
|
||||
public Graph build() {
|
||||
if (builtGraph == null) {
|
||||
IntegerArray[] incomingEdges = new IntegerArray[addedEdges.size()];
|
||||
for (int i = 0; i < addedEdges.size(); ++i) {
|
||||
IntegerArray[] incomingEdges = new IntegerArray[sz];
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
incomingEdges[i] = new IntegerArray(1);
|
||||
}
|
||||
int[][] outgoingEdgeList = new int[addedEdges.size()][];
|
||||
int[][] outgoingEdgeList = new int[sz][];
|
||||
for (int i = 0; i < addedEdges.size(); ++i) {
|
||||
IntegerArray edgeList = addedEdges.get(i);
|
||||
outgoingEdgeList[i] = edgeList != null ? edgeList.getAll() : new int[0];
|
||||
|
@ -55,8 +59,11 @@ public class GraphBuilder {
|
|||
incomingEdges[j].add(i);
|
||||
}
|
||||
}
|
||||
int[][] incomingEdgeList = new int[addedEdges.size()][];
|
||||
for (int i = 0; i < addedEdges.size(); ++i) {
|
||||
for (int i = addedEdges.size(); i < sz; ++i) {
|
||||
outgoingEdgeList[i] = new int[0];
|
||||
}
|
||||
int[][] incomingEdgeList = new int[sz][];
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
incomingEdgeList[i] = incomingEdges[i].getAll();
|
||||
}
|
||||
builtGraph = new GraphImpl(incomingEdgeList, outgoingEdgeList);
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright 2012 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.Map;
|
||||
import org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ConditionalOptimizer {
|
||||
public Map<IdentifiedStatement, Integer> referencedStatements;
|
||||
public ReadWriteStatsBuilder stats;
|
||||
|
||||
public Statement tryOptimizeElse(BlockStatement stmt) {
|
||||
if (stmt.getBody().isEmpty()) {
|
||||
return stmt;
|
||||
}
|
||||
if (!(stmt.getBody().get(0) instanceof ConditionalStatement)) {
|
||||
return stmt;
|
||||
}
|
||||
ConditionalStatement condStmt = (ConditionalStatement)stmt.getBody().get(0);
|
||||
if (condStmt.getAlternative() != null) {
|
||||
return stmt;
|
||||
}
|
||||
if (!(condStmt.getConsequent() instanceof SequentialStatement)) {
|
||||
return stmt;
|
||||
}
|
||||
SequentialStatement condBody = (SequentialStatement)condStmt.getConsequent();
|
||||
if (condBody.getSequence().isEmpty()) {
|
||||
return stmt;
|
||||
}
|
||||
Statement lastStmt = condBody.getSequence().get(condBody.getSequence().size() - 1);
|
||||
if (!(lastStmt instanceof BreakStatement)) {
|
||||
return stmt;
|
||||
}
|
||||
BreakStatement breakStmt = (BreakStatement)lastStmt;
|
||||
if (breakStmt.getTarget() != stmt) {
|
||||
return stmt;
|
||||
}
|
||||
SequentialStatement altBody = new SequentialStatement();
|
||||
for (int i = 1; i < stmt.getBody().size(); ++i) {
|
||||
altBody.getSequence().add(stmt.getBody().get(i));
|
||||
}
|
||||
if (!altBody.getSequence().isEmpty()) {
|
||||
condStmt.setAlternative(altBody.getSequence().size() != 1 ?
|
||||
altBody : altBody.getSequence().get(0));
|
||||
}
|
||||
condBody.getSequence().remove(condBody.getSequence().size() - 1);
|
||||
if (condBody.getSequence().size() == 1) {
|
||||
condStmt.setConsequent(condBody.getSequence().get(0));
|
||||
}
|
||||
stmt.getBody().clear();
|
||||
stmt.getBody().add(condStmt);
|
||||
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
|
||||
if (referencedStatements.get(stmt) > 0) {
|
||||
return stmt;
|
||||
} else {
|
||||
return tryMakeInline(condStmt);
|
||||
}
|
||||
}
|
||||
|
||||
public Statement tryOptimize(BlockStatement stmt) {
|
||||
Expr condition = null;
|
||||
while (true) {
|
||||
if (stmt.getBody().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
if (!(stmt.getBody().get(0) instanceof ConditionalStatement)) {
|
||||
break;
|
||||
}
|
||||
ConditionalStatement condStmt = (ConditionalStatement)stmt.getBody().get(0);
|
||||
if (condStmt.getAlternative() != null) {
|
||||
break;
|
||||
}
|
||||
if (!(condStmt.getConsequent() instanceof BreakStatement)) {
|
||||
break;
|
||||
}
|
||||
BreakStatement breakStmt = (BreakStatement)condStmt.getConsequent();
|
||||
if (breakStmt.getTarget() != stmt) {
|
||||
break;
|
||||
}
|
||||
stmt.getBody().remove(0);
|
||||
if (condition == null) {
|
||||
condition = ExprOptimizer.invert(condStmt.getCondition());
|
||||
} else {
|
||||
condition = Expr.binary(BinaryOperation.AND, condition,
|
||||
ExprOptimizer.invert(condStmt.getCondition()));
|
||||
}
|
||||
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
|
||||
}
|
||||
if (condition == null) {
|
||||
return stmt;
|
||||
}
|
||||
ConditionalStatement newCond = new ConditionalStatement();
|
||||
newCond.setCondition(condition);
|
||||
if (referencedStatements.get(stmt) > 0) {
|
||||
newCond.setConsequent(stmt);
|
||||
} else {
|
||||
if (stmt.getBody().size() == 1) {
|
||||
newCond.setConsequent(stmt.getBody().get(0));
|
||||
} else {
|
||||
SequentialStatement consequent = new SequentialStatement();
|
||||
consequent.getSequence().addAll(stmt.getBody());
|
||||
newCond.setConsequent(consequent);
|
||||
}
|
||||
}
|
||||
return newCond;
|
||||
}
|
||||
|
||||
public void tryOptimize(WhileStatement stmt) {
|
||||
if (stmt.getBody().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!(stmt.getBody().get(0) instanceof ConditionalStatement)) {
|
||||
return;
|
||||
}
|
||||
if (stmt.getCondition() != null) {
|
||||
return;
|
||||
}
|
||||
ConditionalStatement condStmt = (ConditionalStatement)stmt.getBody().get(0);
|
||||
if (condStmt.getAlternative() != null) {
|
||||
return;
|
||||
}
|
||||
if (!(condStmt.getConsequent() instanceof BreakStatement)) {
|
||||
return;
|
||||
}
|
||||
BreakStatement breakStmt = (BreakStatement)condStmt.getConsequent();
|
||||
if (breakStmt.getTarget() != stmt) {
|
||||
return;
|
||||
}
|
||||
stmt.getBody().remove(0);
|
||||
stmt.setCondition(ExprOptimizer.invert(condStmt.getCondition()));
|
||||
}
|
||||
|
||||
public Statement tryMakeInline(ConditionalStatement stmt) {
|
||||
if (!(stmt.getConsequent() instanceof AssignmentStatement) ||
|
||||
!(stmt.getAlternative() instanceof AssignmentStatement)) {
|
||||
return stmt;
|
||||
}
|
||||
AssignmentStatement consequent = (AssignmentStatement)stmt.getConsequent();
|
||||
AssignmentStatement alternative = (AssignmentStatement)stmt.getAlternative();
|
||||
if (!(consequent.getLeftValue() instanceof VariableExpr) ||
|
||||
!(alternative.getLeftValue() instanceof VariableExpr)) {
|
||||
return stmt;
|
||||
}
|
||||
VariableExpr consequentLeft = (VariableExpr)consequent.getLeftValue();
|
||||
VariableExpr alternativeLeft = (VariableExpr)alternative.getLeftValue();
|
||||
if (consequentLeft.getIndex() != alternativeLeft.getIndex()) {
|
||||
return stmt;
|
||||
}
|
||||
AssignmentStatement result = new AssignmentStatement();
|
||||
result.setLeftValue(consequentLeft);
|
||||
ConditionalExpr rightValue = new ConditionalExpr();
|
||||
rightValue.setCondition(stmt.getCondition());
|
||||
rightValue.setConsequent(consequent.getRightValue());
|
||||
rightValue.setAlternative(alternative.getRightValue());
|
||||
result.setRightValue(rightValue);
|
||||
stats.writes[consequentLeft.getIndex()]--;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Statement tryOptimizeSwitch(BlockStatement stmt) {
|
||||
if (stmt.getBody().size() < 2) {
|
||||
return stmt;
|
||||
}
|
||||
if (!(stmt.getBody().get(0) instanceof SwitchStatement)) {
|
||||
return stmt;
|
||||
}
|
||||
SwitchStatement switchStmt = (SwitchStatement)stmt.getBody().get(0);
|
||||
Statement last = stmt.getBody().get(stmt.getBody().size() - 1);
|
||||
if (!(last instanceof BreakStatement) && !(last instanceof ContinueStatement) &&
|
||||
!(last instanceof ReturnStatement) && !(last instanceof ThrowStatement)) {
|
||||
return stmt;
|
||||
}
|
||||
SequentialStatement seqStmt = new SequentialStatement();
|
||||
for (int i = 1; i < stmt.getBody().size(); ++i) {
|
||||
seqStmt.getSequence().add(stmt.getBody().get(i));
|
||||
}
|
||||
int count = referencedStatements.get(stmt);
|
||||
ReferenceCountingVisitor refCounter = new ReferenceCountingVisitor(stmt);
|
||||
switchStmt.acceptVisitor(refCounter);
|
||||
if (count > refCounter.count) {
|
||||
return stmt;
|
||||
}
|
||||
referencedStatements.put(stmt, 0);
|
||||
for (SwitchClause clause : switchStmt.getClauses()) {
|
||||
if (!(clause.getStatement() instanceof BreakStatement)) {
|
||||
continue;
|
||||
}
|
||||
BreakStatement breakStmt = (BreakStatement)clause.getStatement();
|
||||
if (breakStmt.getTarget() == stmt) {
|
||||
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
|
||||
Integer switchRefs = referencedStatements.get(switchStmt);
|
||||
referencedStatements.put(switchStmt, (switchRefs != null ? switchRefs : 0) + 1);
|
||||
breakStmt.setTarget(switchStmt);
|
||||
} else if (breakStmt.getTarget() == switchStmt) {
|
||||
clause.setStatement(seqStmt);
|
||||
}
|
||||
}
|
||||
if (switchStmt.getDefaultClause() instanceof BreakStatement) {
|
||||
BreakStatement breakStmt = (BreakStatement)switchStmt.getDefaultClause();
|
||||
if (breakStmt.getTarget() == stmt) {
|
||||
referencedStatements.put(stmt, referencedStatements.get(stmt) - 1);
|
||||
Integer switchRefs = referencedStatements.get(switchStmt);
|
||||
referencedStatements.put(switchStmt, (switchRefs != null ? switchRefs : 0) + 1);
|
||||
breakStmt.setTarget(switchStmt);
|
||||
} else if (breakStmt.getTarget() == switchStmt) {
|
||||
switchStmt.setDefaultClause(seqStmt);
|
||||
}
|
||||
}
|
||||
return switchStmt;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2012 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 org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ExprOptimizer {
|
||||
public static Expr invert(Expr expr) {
|
||||
if (expr instanceof UnaryExpr) {
|
||||
UnaryExpr unary = (UnaryExpr)expr;
|
||||
if (unary.getOperation() == UnaryOperation.NOT) {
|
||||
return unary.getOperand();
|
||||
}
|
||||
} else if (expr instanceof BinaryExpr) {
|
||||
BinaryExpr binary = (BinaryExpr)expr;
|
||||
Expr a = binary.getFirstOperand();
|
||||
Expr b = binary.getSecondOperand();
|
||||
switch (binary.getOperation()) {
|
||||
case EQUALS:
|
||||
return Expr.binary(BinaryOperation.NOT_EQUALS, a, b);
|
||||
case NOT_EQUALS:
|
||||
return Expr.binary(BinaryOperation.EQUALS, a, b);
|
||||
case LESS:
|
||||
return Expr.binary(BinaryOperation.GREATER_OR_EQUALS, a, b);
|
||||
case LESS_OR_EQUALS:
|
||||
return Expr.binary(BinaryOperation.GREATER, a, b);
|
||||
case GREATER:
|
||||
return Expr.binary(BinaryOperation.LESS_OR_EQUALS, a, b);
|
||||
case GREATER_OR_EQUALS:
|
||||
return Expr.binary(BinaryOperation.LESS, a, b);
|
||||
case STRICT_EQUALS:
|
||||
return Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, a, b);
|
||||
case STRICT_NOT_EQUALS:
|
||||
return Expr.binary(BinaryOperation.STRICT_EQUALS, a, b);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Expr.invert(expr);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,16 @@
|
|||
*/
|
||||
package org.teavm.javascript;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.*;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.teavm.codegen.DefaultAliasProvider;
|
||||
import org.teavm.codegen.DefaultNamingStrategy;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.common.*;
|
||||
import org.teavm.javascript.ast.*;
|
||||
import org.teavm.model.*;
|
||||
|
@ -201,9 +210,50 @@ public class MethodDecompiler {
|
|||
this.loops = loops;
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
public static void main(String... args) throws IOException {
|
||||
ClassHolderSource source = new ClassHolderSource();
|
||||
Parser parser = new Parser();
|
||||
parser.parseClass(null);
|
||||
ClassHolder arrayListCls = Parser.parseClass(readClass(ArrayList.class.getName()));
|
||||
source.putClassHolder(arrayListCls);
|
||||
source.putClassHolder(Parser.parseClass(readClass(AbstractList.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(StringBuilder.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(IllegalArgumentException.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(IndexOutOfBoundsException.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(Exception.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(RuntimeException.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(Throwable.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(System.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(Object.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(Arrays.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(ArrayList.class.getName() + "$ListItr")));
|
||||
source.putClassHolder(Parser.parseClass(readClass(ArrayList.class.getName() + "$Itr")));
|
||||
source.putClassHolder(Parser.parseClass(readClass(ArrayList.class.getName() + "$SubList")));
|
||||
source.putClassHolder(Parser.parseClass(readClass(Collection.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(ObjectOutputStream.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(ObjectInputStream.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(ConcurrentModificationException.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(Math.class.getName())));
|
||||
source.putClassHolder(Parser.parseClass(readClass(OutOfMemoryError.class.getName())));
|
||||
MethodDecompiler decompiler = new MethodDecompiler(source);
|
||||
DefaultAliasProvider aliasProvider = new DefaultAliasProvider();
|
||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, source);
|
||||
SourceWriter writer = new SourceWriter(naming);
|
||||
Renderer renderer = new Renderer(writer, source);
|
||||
Optimizer optimizer = new Optimizer();
|
||||
for (MethodHolder method : arrayListCls.getMethods()) {
|
||||
RenderableMethod renderableMethod = decompiler.decompile(method);
|
||||
optimizer.optimize(renderableMethod);
|
||||
renderer.render(renderableMethod);
|
||||
}
|
||||
System.out.println(writer);
|
||||
}
|
||||
|
||||
private static ClassNode readClass(String className) throws IOException {
|
||||
ClassLoader classLoader = MethodDecompiler.class.getClassLoader();
|
||||
try (InputStream input = classLoader.getResourceAsStream(className.replace('.', '/') + ".class")) {
|
||||
ClassReader reader = new ClassReader(input);
|
||||
ClassNode node = new ClassNode();
|
||||
reader.accept(node, 0);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
47
teavm-core/src/main/java/org/teavm/javascript/Optimizer.java
Normal file
47
teavm-core/src/main/java/org/teavm/javascript/Optimizer.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012 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 org.teavm.javascript.ast.RenderableMethod;
|
||||
import org.teavm.javascript.ast.Statement;
|
||||
import org.teavm.model.MethodHolder;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class Optimizer {
|
||||
public Statement optimize(MethodHolder method, Statement statement) {
|
||||
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getProgram().variableCount());
|
||||
statement.acceptVisitor(stats);
|
||||
OptimizingVisitor optimizer = new OptimizingVisitor(stats);
|
||||
statement.acceptVisitor(optimizer);
|
||||
return optimizer.resultStmt;
|
||||
}
|
||||
|
||||
public void optimize(RenderableMethod method) {
|
||||
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariableCount());
|
||||
method.getBody().acceptVisitor(stats);
|
||||
OptimizingVisitor optimizer = new OptimizingVisitor(stats);
|
||||
method.getBody().acceptVisitor(optimizer);
|
||||
method.setBody(optimizer.resultStmt);
|
||||
int paramCount = method.getMetadata().parameterCount();
|
||||
UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariableCount());
|
||||
method.getBody().acceptVisitor(unusedEliminator);
|
||||
method.setVariableCount(unusedEliminator.lastIndex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* Copyright 2012 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 OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||
public Expr resultExpr;
|
||||
public Statement resultStmt;
|
||||
private ReadWriteStatsBuilder stats;
|
||||
private Map<IdentifiedStatement, IdentifiedStatement> copies = new HashMap<>();
|
||||
private Map<IdentifiedStatement, Integer> referencedStatements = new HashMap<>();
|
||||
private ConditionalOptimizer conditionalOptimizer = new ConditionalOptimizer();
|
||||
private List<Statement> resultSequence;
|
||||
|
||||
public OptimizingVisitor(ReadWriteStatsBuilder stats) {
|
||||
this.stats = stats;
|
||||
conditionalOptimizer.referencedStatements = referencedStatements;
|
||||
conditionalOptimizer.stats = stats;
|
||||
}
|
||||
|
||||
private static boolean isZero(Expr expr) {
|
||||
return expr instanceof ConstantExpr &&
|
||||
Integer.valueOf(0).equals(((ConstantExpr)expr).getValue());
|
||||
}
|
||||
|
||||
private static boolean isComparison(Expr expr) {
|
||||
return expr instanceof BinaryExpr &&
|
||||
((BinaryExpr)expr).getOperation() == BinaryOperation.COMPARE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryExpr expr) {
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
Expr b = resultExpr;
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
Expr a = resultExpr;
|
||||
Expr p = a;
|
||||
Expr q = b;
|
||||
boolean invert = false;
|
||||
if (isZero(p)) {
|
||||
Expr tmp = p;
|
||||
p = q;
|
||||
q = tmp;
|
||||
invert = true;
|
||||
}
|
||||
if (isComparison(p) && isZero(q)) {
|
||||
switch (expr.getOperation()) {
|
||||
case EQUALS:
|
||||
case NOT_EQUALS:
|
||||
case LESS:
|
||||
case LESS_OR_EQUALS:
|
||||
case GREATER:
|
||||
case GREATER_OR_EQUALS: {
|
||||
BinaryExpr comparison = (BinaryExpr)p;
|
||||
Expr result = BinaryExpr.binary(expr.getOperation(),
|
||||
comparison.getFirstOperand(), comparison.getSecondOperand());
|
||||
if (invert) {
|
||||
result = ExprOptimizer.invert(result);
|
||||
}
|
||||
resultExpr = result;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
resultExpr = Expr.binary(expr.getOperation(), a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr expr) {
|
||||
expr.getOperand().acceptVisitor(this);
|
||||
Expr operand = resultExpr;
|
||||
resultExpr = Expr.unary(expr.getOperation(), operand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalExpr expr) {
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
Expr cond = resultExpr;
|
||||
expr.getConsequent().acceptVisitor(this);
|
||||
Expr consequent = resultExpr;
|
||||
expr.getAlternative().acceptVisitor(this);
|
||||
Expr alternative = resultExpr;
|
||||
ConditionalExpr result = new ConditionalExpr();
|
||||
result.setCondition(cond);
|
||||
result.setConsequent(consequent);
|
||||
result.setAlternative(alternative);
|
||||
resultExpr = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstantExpr expr) {
|
||||
resultExpr = Expr.constant(expr.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(VariableExpr expr) {
|
||||
int index = expr.getIndex();
|
||||
resultExpr = Expr.var(index);
|
||||
if (stats.reads[index] != 1 || stats.writes[index] != 1) {
|
||||
return;
|
||||
}
|
||||
if (resultSequence.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Statement last = resultSequence.get(resultSequence.size() - 1);
|
||||
if (!(last instanceof AssignmentStatement)) {
|
||||
return;
|
||||
}
|
||||
AssignmentStatement assignment = (AssignmentStatement)last;
|
||||
if (!(assignment.getLeftValue() instanceof VariableExpr)) {
|
||||
return;
|
||||
}
|
||||
VariableExpr var = (VariableExpr)assignment.getLeftValue();
|
||||
if (var.getIndex() == index) {
|
||||
resultSequence.remove(resultSequence.size() - 1);
|
||||
assignment.getRightValue().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubscriptExpr expr) {
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
Expr index = resultExpr;
|
||||
expr.getArray().acceptVisitor(this);
|
||||
Expr array = resultExpr;
|
||||
resultExpr = Expr.subscript(array, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InvocationExpr expr) {
|
||||
Expr[] args = new Expr[expr.getArguments().size()];
|
||||
for (int i = expr.getArguments().size() - 1; i >= 0; --i) {
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
args[i] = resultExpr;
|
||||
}
|
||||
switch (expr.getType()) {
|
||||
case STATIC:
|
||||
resultExpr = Expr.invokeStatic(expr.getClassName(), expr.getMethod(), args);
|
||||
break;
|
||||
case DYNAMIC:
|
||||
resultExpr = Expr.invoke(expr.getClassName(), expr.getMethod(), args[0], Arrays.copyOfRange(
|
||||
args, 1, args.length));
|
||||
break;
|
||||
case SPECIAL:
|
||||
resultExpr = Expr.invokeSpecial(expr.getClassName(), expr.getMethod(), args[0], Arrays.copyOfRange(
|
||||
args, 1, args.length));
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
resultExpr = Expr.constructObject(expr.getClassName(), expr.getMethod(), args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryApplyConstructor(InvocationExpr expr) {
|
||||
if (!expr.getMethod().getName().equals("<init>")) {
|
||||
return false;
|
||||
}
|
||||
if (resultSequence == null || resultSequence.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Statement last = resultSequence.get(resultSequence.size() - 1);
|
||||
if (!(last instanceof AssignmentStatement)) {
|
||||
return false;
|
||||
}
|
||||
AssignmentStatement assignment = (AssignmentStatement)last;
|
||||
if (!(assignment.getLeftValue() instanceof VariableExpr)) {
|
||||
return false;
|
||||
}
|
||||
VariableExpr var = (VariableExpr)assignment.getLeftValue();
|
||||
if (!(expr.getArguments().get(0) instanceof VariableExpr)) {
|
||||
return false;
|
||||
}
|
||||
VariableExpr target = (VariableExpr)expr.getArguments().get(0);
|
||||
if (target.getIndex() != var.getIndex()) {
|
||||
return false;
|
||||
}
|
||||
if (!(assignment.getRightValue() instanceof NewExpr)) {
|
||||
return false;
|
||||
}
|
||||
NewExpr constructed = (NewExpr)assignment.getRightValue();
|
||||
if (!constructed.getConstructedClass().equals(expr.getClassName())) {
|
||||
return false;
|
||||
}
|
||||
Expr[] args = expr.getArguments().toArray(new Expr[0]);
|
||||
args = Arrays.copyOfRange(args, 1, args.length);
|
||||
assignment.setRightValue(Expr.constructObject(expr.getClassName(), expr.getMethod(), args));
|
||||
stats.reads[var.getIndex()]--;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(QualificationExpr expr) {
|
||||
expr.getQualified().acceptVisitor(this);
|
||||
Expr qualified = resultExpr;
|
||||
resultExpr = Expr.qualify(qualified, expr.getClassName(), expr.getField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewExpr expr) {
|
||||
resultExpr = Expr.createObject(expr.getConstructedClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewArrayExpr expr) {
|
||||
expr.getLength().acceptVisitor(this);
|
||||
Expr length = resultExpr;
|
||||
resultExpr = Expr.createArray(expr.getType(), length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewMultiArrayExpr expr) {
|
||||
NewMultiArrayExpr result = new NewMultiArrayExpr();
|
||||
result.setType(expr.getType());
|
||||
for (Expr dimension : expr.getDimensions()) {
|
||||
dimension.acceptVisitor(this);
|
||||
result.getDimensions().add(resultExpr);
|
||||
}
|
||||
resultExpr = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InstanceOfExpr expr) {
|
||||
expr.getExpr().acceptVisitor(this);
|
||||
Expr value = resultExpr;
|
||||
resultExpr = Expr.instanceOf(value, expr.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StaticClassExpr expr) {
|
||||
resultExpr = Expr.staticClass(expr.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
if (statement.getLeftValue() == null) {
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
if (resultExpr instanceof InvocationExpr &&
|
||||
tryApplyConstructor((InvocationExpr)resultExpr)) {
|
||||
resultStmt = new SequentialStatement();
|
||||
} else {
|
||||
resultStmt = Statement.assign(null, resultExpr);
|
||||
}
|
||||
} else {
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
Expr right = resultExpr;
|
||||
Expr left;
|
||||
if (statement.getLeftValue() instanceof VariableExpr) {
|
||||
VariableExpr leftVar = (VariableExpr)statement.getLeftValue();
|
||||
left = statement.getLeftValue();
|
||||
if (stats.reads[leftVar.getIndex()] == 0) {
|
||||
left = null;
|
||||
} else {
|
||||
left = statement.getLeftValue();
|
||||
}
|
||||
} else {
|
||||
statement.getLeftValue().acceptVisitor(this);
|
||||
left = resultExpr;
|
||||
}
|
||||
resultStmt = Statement.assign(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Statement> processSequence(List<Statement> statements, boolean strict) {
|
||||
List<Statement> backup = resultSequence;
|
||||
List<Statement> result = new ArrayList<>();
|
||||
if (strict) {
|
||||
resultSequence = result;
|
||||
}
|
||||
for (Statement part : statements) {
|
||||
part.acceptVisitor(this);
|
||||
if (resultStmt != null) {
|
||||
resultSequence = result;
|
||||
if (resultStmt instanceof SequentialStatement) {
|
||||
result.addAll(((SequentialStatement)resultStmt).getSequence());
|
||||
} else {
|
||||
result.add(resultStmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
resultSequence = backup;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
List<Statement> statements = processSequence(statement.getSequence(), false);
|
||||
if (statements.isEmpty()) {
|
||||
resultStmt = null;
|
||||
return;
|
||||
}
|
||||
if (statements.size() == 1) {
|
||||
resultStmt = statements.get(0);
|
||||
} else {
|
||||
SequentialStatement result = new SequentialStatement();
|
||||
result.getSequence().addAll(statements);
|
||||
resultStmt = result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
Expr predicate = resultExpr;
|
||||
List<Statement> sequenceBackup = resultSequence;
|
||||
resultSequence = new ArrayList<>();
|
||||
statement.getConsequent().acceptVisitor(this);
|
||||
Statement consequent = resultStmt;
|
||||
Statement alternative = null;
|
||||
if (statement.getAlternative() != null) {
|
||||
statement.getAlternative().acceptVisitor(this);
|
||||
alternative = resultStmt;
|
||||
}
|
||||
if (consequent == null) {
|
||||
if (alternative != null) {
|
||||
Statement tmp = alternative;
|
||||
alternative = consequent;
|
||||
consequent = tmp;
|
||||
predicate = ExprOptimizer.invert(predicate);
|
||||
} else {
|
||||
consequent = Statement.empty();
|
||||
}
|
||||
}
|
||||
resultStmt = conditionalOptimizer.tryMakeInline(
|
||||
(ConditionalStatement)Statement.cond(predicate, consequent, alternative));
|
||||
resultSequence = sequenceBackup;
|
||||
}
|
||||
|
||||
private void visitIdentified(IdentifiedStatement stmt, IdentifiedStatement copy) {
|
||||
copies.put(stmt, copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
SwitchStatement result = new SwitchStatement();
|
||||
result.setId(statement.getId());
|
||||
visitIdentified(statement, result);
|
||||
statement.getValue().acceptVisitor(this);
|
||||
result.setValue(resultExpr);
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
clause.getStatement().acceptVisitor(this);
|
||||
SwitchClause resultClause = new SwitchClause();
|
||||
resultClause.setConditions(clause.getConditions());
|
||||
resultClause.setStatement(resultStmt != null ? resultStmt : Statement.empty());
|
||||
result.getClauses().add(resultClause);
|
||||
}
|
||||
if (statement.getDefaultClause() != null) {
|
||||
statement.getDefaultClause().acceptVisitor(this);
|
||||
} else {
|
||||
resultStmt = null;
|
||||
}
|
||||
result.setDefaultClause(resultStmt != null ? resultStmt : Statement.empty());
|
||||
resultStmt = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
WhileStatement result = new WhileStatement();
|
||||
result.setId(statement.getId());
|
||||
visitIdentified(statement, result);
|
||||
List<Statement> statements = processSequence(statement.getBody(), false);
|
||||
if (statement.getCondition() != null) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
result.setCondition(resultExpr);
|
||||
} else {
|
||||
result.setCondition(null);
|
||||
}
|
||||
result.getBody().addAll(statements);
|
||||
conditionalOptimizer.tryOptimize(result);
|
||||
resultStmt = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
BlockStatement result = new BlockStatement();
|
||||
result.setId(statement.getId());
|
||||
visitIdentified(statement, result);
|
||||
List<Statement> statements = processSequence(statement.getBody(), false);
|
||||
result.getBody().addAll(statements);
|
||||
if (referencedStatements.containsKey(result)) {
|
||||
resultStmt = conditionalOptimizer.tryOptimize(result);
|
||||
} else {
|
||||
SequentialStatement altResult = new SequentialStatement();
|
||||
altResult.getSequence().addAll(result.getBody());
|
||||
resultStmt = altResult;
|
||||
}
|
||||
if (resultStmt instanceof BlockStatement) {
|
||||
resultStmt = conditionalOptimizer.tryOptimizeElse((BlockStatement)resultStmt);
|
||||
}
|
||||
if (resultStmt instanceof BlockStatement) {
|
||||
resultStmt = conditionalOptimizer.tryOptimizeSwitch((BlockStatement)resultStmt);
|
||||
}
|
||||
if (resultStmt instanceof ConditionalStatement) {
|
||||
ConditionalStatement conditional = (ConditionalStatement)resultStmt;
|
||||
conditional.getCondition().acceptVisitor(this);
|
||||
conditional.setCondition(resultExpr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
BreakStatement result = new BreakStatement();
|
||||
if (statement.getTarget() != null) {
|
||||
IdentifiedStatement targetCopy = copies.get(statement.getTarget());
|
||||
result.setTarget(targetCopy);
|
||||
Integer refCount = referencedStatements.get(targetCopy);
|
||||
if (refCount == null) {
|
||||
refCount = 0;
|
||||
}
|
||||
referencedStatements.put(targetCopy, refCount + 1);
|
||||
}
|
||||
resultStmt = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
ContinueStatement result = new ContinueStatement();
|
||||
if (statement.getTarget() != null) {
|
||||
IdentifiedStatement targetCopy = copies.get(statement.getTarget());
|
||||
result.setTarget(targetCopy);
|
||||
Integer refCount = referencedStatements.get(targetCopy);
|
||||
if (refCount == null) {
|
||||
refCount = 0;
|
||||
}
|
||||
referencedStatements.put(targetCopy, refCount + 1);
|
||||
}
|
||||
resultStmt = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
if (statement.getResult() == null) {
|
||||
resultStmt = Statement.exitFunction(null);
|
||||
} else {
|
||||
statement.getResult().acceptVisitor(this);
|
||||
resultStmt = Statement.exitFunction(resultExpr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
statement.getException().acceptVisitor(this);
|
||||
resultStmt = Statement.raiseException(resultExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IncrementStatement statement) {
|
||||
resultStmt = Statement.increment(statement.getVar(), statement.getAmount());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright 2012 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 org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ReadWriteStatsBuilder implements StatementVisitor, ExprVisitor {
|
||||
public int[] reads;
|
||||
public int[] writes;
|
||||
|
||||
public ReadWriteStatsBuilder(int variableCount) {
|
||||
reads = new int[variableCount];
|
||||
writes = new int[variableCount];
|
||||
}
|
||||
|
||||
@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) {
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
expr.getConsequent().acceptVisitor(this);
|
||||
expr.getAlternative().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstantExpr expr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(VariableExpr expr) {
|
||||
reads[expr.getIndex()]++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubscriptExpr expr) {
|
||||
expr.getArray().acceptVisitor(this);
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InvocationExpr expr) {
|
||||
for (Expr arg : expr.getArguments()) {
|
||||
arg.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(QualificationExpr expr) {
|
||||
expr.getQualified().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewExpr 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StaticClassExpr expr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
if (statement.getLeftValue() != null) {
|
||||
if (statement.getLeftValue() instanceof VariableExpr) {
|
||||
VariableExpr leftVar = (VariableExpr)statement.getLeftValue();
|
||||
writes[leftVar.getIndex()]++;
|
||||
} else {
|
||||
statement.getLeftValue().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
for (Statement part : statement.getSequence()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
statement.getConsequent().acceptVisitor(this);
|
||||
if (statement.getAlternative() != null) {
|
||||
statement.getAlternative().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
statement.getValue().acceptVisitor(this);
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
clause.getStatement().acceptVisitor(this);
|
||||
}
|
||||
if (statement.getDefaultClause() != null) {
|
||||
statement.getDefaultClause().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
if (statement.getCondition() != null) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
}
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
if (statement.getResult() != null) {
|
||||
statement.getResult().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
statement.getException().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IncrementStatement statement) {
|
||||
reads[statement.getVar()]++;
|
||||
writes[statement.getVar()]++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2012 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 org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class ReferenceCountingVisitor implements StatementVisitor {
|
||||
private IdentifiedStatement target;
|
||||
public int count;
|
||||
|
||||
public ReferenceCountingVisitor(IdentifiedStatement target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
for (Statement part : statement.getSequence()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
statement.getConsequent().acceptVisitor(this);
|
||||
if (statement.getAlternative() != null) {
|
||||
statement.getAlternative().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
clause.getStatement().acceptVisitor(this);
|
||||
}
|
||||
statement.getDefaultClause().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
if (statement.getTarget() == target) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
if (statement.getTarget() == target) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IncrementStatement statement) {
|
||||
}
|
||||
|
||||
}
|
|
@ -210,7 +210,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
first = false;
|
||||
writer.append(variableName(i));
|
||||
}
|
||||
writer.append(";\n");
|
||||
writer.append(";").newLine();
|
||||
}
|
||||
method.getBody().acceptVisitor(this);
|
||||
writer.outdent().append("}").newLine();
|
||||
|
@ -240,7 +240,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
writer.append(") {").newLine().indent();
|
||||
statement.getConsequent().acceptVisitor(this);
|
||||
if (statement.getAlternative() != null) {
|
||||
writer.outdent().append("} else {\n").indent().newLine();
|
||||
writer.outdent().append("} else {").indent().newLine();
|
||||
statement.getAlternative().acceptVisitor(this);
|
||||
}
|
||||
writer.outdent().append("}").newLine();
|
||||
|
@ -354,9 +354,9 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
--index;
|
||||
if (index < variableNames.length()) {
|
||||
return String.valueOf(variableNames.charAt(index));
|
||||
return Character.toString(variableNames.charAt(index));
|
||||
} else {
|
||||
return String.valueOf(variableNames.charAt(index % variableNames.length())) +
|
||||
return Character.toString(variableNames.charAt(index % variableNames.length())) +
|
||||
index / variableNames.length();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright 2012 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.Arrays;
|
||||
import org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
|
||||
int[] indexes;
|
||||
int lastIndex;
|
||||
|
||||
public UnusedVariableEliminator(int parameterCount, int variableCount) {
|
||||
indexes = new int[variableCount];
|
||||
Arrays.fill(indexes, -1);
|
||||
for (int i = 0; i <= parameterCount; ++i) {
|
||||
indexes[i] = lastIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
if (statement.getLeftValue() != null) {
|
||||
statement.getLeftValue().acceptVisitor(this);
|
||||
}
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
for (Statement part : statement.getSequence()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
statement.getConsequent().acceptVisitor(this);
|
||||
if (statement.getAlternative() != null) {
|
||||
statement.getAlternative().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
statement.getValue().acceptVisitor(this);
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
clause.getStatement().acceptVisitor(this);
|
||||
}
|
||||
statement.getDefaultClause().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
if (statement.getCondition() != null) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
}
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
if (statement.getResult() != null) {
|
||||
statement.getResult().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
statement.getException().acceptVisitor(this);
|
||||
}
|
||||
|
||||
private int renumber(int var) {
|
||||
int index = indexes[var];
|
||||
if (index == -1) {
|
||||
index = lastIndex++;
|
||||
indexes[var] = index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IncrementStatement statement) {
|
||||
statement.setVar(renumber(statement.getVar()));
|
||||
}
|
||||
|
||||
@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) {
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
expr.getConsequent().acceptVisitor(this);
|
||||
expr.getAlternative().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstantExpr expr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(VariableExpr expr) {
|
||||
expr.setIndex(renumber(expr.getIndex()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubscriptExpr expr) {
|
||||
expr.getArray().acceptVisitor(this);
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InvocationExpr expr) {
|
||||
for (Expr arg : expr.getArguments()) {
|
||||
arg.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(QualificationExpr expr) {
|
||||
expr.getQualified().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewExpr 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StaticClassExpr expr) {
|
||||
}
|
||||
}
|
|
@ -67,6 +67,7 @@ public class Program {
|
|||
for (int i = 0; i < basicBlocks.size(); ++i) {
|
||||
BasicBlock block = basicBlocks.get(i);
|
||||
if (block != null) {
|
||||
block.setIndex(sz);
|
||||
basicBlocks.set(sz++, block);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,7 +300,7 @@ public class ProgramParser {
|
|||
insn.setCondition(getVariable(--currentDepth));
|
||||
insn.getEntries().addAll(Arrays.asList(table));
|
||||
builder.add(insn);
|
||||
int defaultIndex = labelIndexes.get(insn);
|
||||
int defaultIndex = labelIndexes.get(dflt);
|
||||
insn.setDefaultTarget(getBasicBlock(defaultIndex));
|
||||
nextIndexes[labels.length] = defaultIndex;
|
||||
}
|
||||
|
|
0
teavm-core/src/main/resources/.gitignore
vendored
Normal file
0
teavm-core/src/main/resources/.gitignore
vendored
Normal file
0
teavm-core/src/test/java/.gitignore
vendored
Normal file
0
teavm-core/src/test/java/.gitignore
vendored
Normal file
0
teavm-core/src/test/resources/.gitignore
vendored
Normal file
0
teavm-core/src/test/resources/.gitignore
vendored
Normal file
Loading…
Reference in New Issue
Block a user