From 692bfdd73186908e15f3485b18621538cc0f1b84 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 30 Jan 2014 17:13:24 +0400 Subject: [PATCH] Fixes issues in if statement AST optimizer --- .../teavm/javascript/OptimizingVisitor.java | 120 +++++++++--------- .../java/org/teavm/javascript/Renderer.java | 27 ++-- 2 files changed, 81 insertions(+), 66 deletions(-) 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 32606d30d..5f3ae485f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -301,94 +301,101 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { return result; } - private void eliminateRedundantBreaks(List statements, Set currentExits, - Set exits) { + private void eliminateRedundantBreaks(List statements, IdentifiedStatement exit) { if (statements.isEmpty()) { return; } Statement last = statements.get(statements.size() - 1); - if (last instanceof BreakStatement) { + if (last instanceof BreakStatement && exit != null) { IdentifiedStatement target = ((BreakStatement)last).getTarget(); - if (exits.contains(target)) { + if (exit == target) { statements.remove(statements.size() - 1); } } if (statements.isEmpty()) { return; } - Set nestedExits = new HashSet<>(); - nestedExits.addAll(currentExits); for (int i = 0; i < statements.size(); ++i) { - if (i == statements.size() - 1) { - nestedExits.addAll(exits); - } Statement stmt = statements.get(i); if (stmt instanceof ConditionalStatement) { ConditionalStatement cond = (ConditionalStatement)stmt; - last = cond.getConsequent().get(cond.getConsequent().size() - 1); - if (last instanceof BreakStatement) { - BreakStatement breakStmt = (BreakStatement)last; - if (currentExits.contains(breakStmt.getTarget()) || exits.contains(breakStmt.getTarget())) { - int refs = referencedStatements.get(breakStmt.getTarget()); - referencedStatements.put(breakStmt.getTarget(), refs - 1); - cond.getConsequent().remove(cond.getConsequent().size() - 1); - List remaining = statements.subList(i + 1, statements.size()); - cond.getAlternative().addAll(remaining); - remaining.clear(); - visit(cond); - if (resultStmt == cond) { - eliminateRedundantBreaks(cond.getConsequent(), - Collections.emptySet(), nestedExits); - eliminateRedundantBreaks(cond.getAlternative(), - Collections.emptySet(), nestedExits); - } else { - statements.set(i, resultStmt); + check_conditional: { + last = cond.getConsequent().isEmpty() ? null : + cond.getConsequent().get(cond.getConsequent().size() - 1); + if (last instanceof BreakStatement) { + BreakStatement breakStmt = (BreakStatement)last; + if (exit != null && exit == breakStmt.getTarget()) { + int refs = referencedStatements.get(breakStmt.getTarget()); + referencedStatements.put(breakStmt.getTarget(), refs - 1); + cond.getConsequent().remove(cond.getConsequent().size() - 1); + List remaining = statements.subList(i + 1, statements.size()); + cond.getAlternative().addAll(remaining); + remaining.clear(); + break check_conditional; + } + } + last = cond.getAlternative().isEmpty() ? null : + cond.getAlternative().get(cond.getAlternative().size() - 1); + if (last instanceof BreakStatement) { + BreakStatement breakStmt = (BreakStatement)last; + if (exit != null && exit == breakStmt.getTarget()) { + int refs = referencedStatements.get(breakStmt.getTarget()); + referencedStatements.put(breakStmt.getTarget(), refs - 1); + cond.getAlternative().remove(cond.getConsequent().size() - 1); + List remaining = statements.subList(i + 1, statements.size()); + cond.getConsequent().addAll(remaining); + remaining.clear(); + break check_conditional; } - break; } } - last = cond.getAlternative().isEmpty() ? null : - cond.getAlternative().get(cond.getAlternative().size() - 1); - if (last instanceof BreakStatement) { - BreakStatement breakStmt = (BreakStatement)last; - if (currentExits.contains(breakStmt.getTarget()) || exits.contains(breakStmt.getTarget())) { - int refs = referencedStatements.get(breakStmt.getTarget()); - referencedStatements.put(breakStmt.getTarget(), refs - 1); - cond.getAlternative().remove(cond.getConsequent().size() - 1); - List remaining = statements.subList(i + 1, statements.size()); - cond.getConsequent().addAll(remaining); - remaining.clear(); - visit(cond); - if (resultStmt == cond) { - eliminateRedundantBreaks(cond.getConsequent(), - Collections.emptySet(), nestedExits); - eliminateRedundantBreaks(cond.getAlternative(), - Collections.emptySet(), nestedExits); + if (i == statements.size() - 1) { + eliminateRedundantBreaks(cond.getConsequent(), exit); + eliminateRedundantBreaks(cond.getAlternative(), exit); + } + normalizeConditional(cond); + if (cond.getConsequent().size() == 1 && cond.getConsequent().get(0) instanceof ConditionalStatement) { + ConditionalStatement innerCond = (ConditionalStatement)cond.getConsequent().get(0); + if (innerCond.getAlternative().isEmpty()) { + if (cond.getAlternative().isEmpty()) { + cond.getConsequent().clear(); + cond.getConsequent().addAll(innerCond.getConsequent()); + cond.setCondition(Expr.binary(BinaryOperation.AND, cond.getCondition(), + innerCond.getCondition())); + } else { + cond.setCondition(ExprOptimizer.invert(cond.getCondition())); + cond.getConsequent().clear(); + cond.getConsequent().addAll(cond.getAlternative()); + cond.getAlternative().clear(); + cond.getAlternative().add(innerCond); } - statements.set(i, resultStmt); - break; + --i; } } } else if (stmt instanceof BlockStatement) { BlockStatement nestedBlock = (BlockStatement)stmt; - eliminateRedundantBreaks(nestedBlock.getBody(), - Collections.singleton(nestedBlock), nestedExits); + eliminateRedundantBreaks(nestedBlock.getBody(), nestedBlock); } else if (stmt instanceof WhileStatement) { WhileStatement whileStmt = (WhileStatement)stmt; - eliminateRedundantBreaks(whileStmt.getBody(), Collections.emptySet(), - Collections.emptySet()); + eliminateRedundantBreaks(whileStmt.getBody(), null); } else if (stmt instanceof SwitchStatement) { SwitchStatement switchStmt = (SwitchStatement)stmt; for (SwitchClause clause : switchStmt.getClauses()) { - eliminateRedundantBreaks(clause.getBody(), Collections.emptySet(), - Collections.emptySet()); + eliminateRedundantBreaks(clause.getBody(), null); } - eliminateRedundantBreaks(switchStmt.getDefaultClause(), null, - Collections.emptySet()); + eliminateRedundantBreaks(switchStmt.getDefaultClause(), null); } } } + private void normalizeConditional(ConditionalStatement stmt) { + if (stmt.getConsequent().isEmpty()) { + stmt.getConsequent().addAll(stmt.getAlternative()); + stmt.getAlternative().clear(); + stmt.setCondition(ExprOptimizer.invert(stmt.getCondition())); + } + } + @Override public void visit(SequentialStatement statement) { List statements = processSequence(statement.getSequence(), false); @@ -453,8 +460,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(BlockStatement statement) { List statements = processSequence(statement.getBody(), false); - eliminateRedundantBreaks(statements, Collections.singleton(statement), - Collections.emptySet()); + eliminateRedundantBreaks(statements, statement); if (referencedStatements.get(statement).equals(0)) { SequentialStatement result = new SequentialStatement(); result.getSequence().addAll(statements); diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index cd1774b84..01ee5f0eb 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -385,17 +385,26 @@ public class Renderer implements ExprVisitor, StatementVisitor { @Override public void visit(ConditionalStatement statement) { try { - writer.append("if").ws().append("("); - statement.getCondition().acceptVisitor(this); - writer.append(")").ws().append("{").softNewLine().indent(); - for (Statement part : statement.getConsequent()) { - part.acceptVisitor(this); - } - if (!statement.getAlternative().isEmpty()) { - writer.outdent().append("}").ws().append("else").ws().append("{").indent().softNewLine(); - for (Statement part : statement.getAlternative()) { + while (true) { + writer.append("if").ws().append("("); + statement.getCondition().acceptVisitor(this); + writer.append(")").ws().append("{").softNewLine().indent(); + for (Statement part : statement.getConsequent()) { part.acceptVisitor(this); } + if (!statement.getAlternative().isEmpty()) { + writer.outdent().append("}").ws().append("else").ws(); + if (statement.getAlternative().size() == 1 && + statement.getAlternative().get(0) instanceof ConditionalStatement) { + statement = (ConditionalStatement)statement.getAlternative().get(0); + continue; + } + writer.append("{").indent().softNewLine(); + for (Statement part : statement.getAlternative()) { + part.acceptVisitor(this); + } + } + break; } writer.outdent().append("}").softNewLine(); } catch (IOException e) {