Author: sco...@google.com Date: Thu Jun 11 12:08:45 2009 New Revision: 5540
Modified: trunk/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java trunk/dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java Log: JsStaticEval now optimizes certain if statements to conditional operators. if (a()) {b()} else {c()} -> a()?b():c() if (a()) {b()} -> a()&&b() if (a()) {} else {b()} -> a()||b() Patch by: mmastrac Suggested by: me Review by: me Modified: trunk/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java ============================================================================== --- trunk/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java (original) +++ trunk/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java Thu Jun 11 12:08:45 2009 @@ -352,32 +352,50 @@ } else { boolean thenIsEmpty = isEmpty(thenStmt); boolean elseIsEmpty = isEmpty(elseStmt); - + JsExpression thenExpr = extractExpression(thenStmt); + JsExpression elseExpr = extractExpression(elseStmt); + if (thenIsEmpty && elseIsEmpty) { + // Convert "if (a()) {}" => "a()". ctx.replaceMe(expr.makeStmt()); + } else if (thenExpr != null && elseExpr != null) { + // Convert "if (a()) {b()} else {c()}" => "a()?b():c()". + sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class, + "Replaced if statement with conditional"); + + JsConditional cond = new JsConditional(sourceInfo, x.getIfExpr(), + thenExpr, elseExpr); + ctx.replaceMe(accept(cond.makeStmt())); + } else if (thenIsEmpty && elseExpr != null) { + // Convert "if (a()) {} else {b()}" => a()||b(). + sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class, + "Replaced if statement with ||"); + + JsBinaryOperation op = new JsBinaryOperation(sourceInfo, + JsBinaryOperator.OR, x.getIfExpr(), elseExpr); + ctx.replaceMe(accept(op.makeStmt())); } else if (thenIsEmpty && !elseIsEmpty) { - /* - * If the then block is blank, but the else statement has statements, - * invert the test - */ + // Convert "if (a()) {} else {stuff}" => "if (!a()) {stuff}". sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class, "Simplified if with empty then statement"); JsUnaryOperation negatedOperation = new JsPrefixOperation(sourceInfo, JsUnaryOperator.NOT, x.getIfExpr()); JsIf newIf = new JsIf(sourceInfo, negatedOperation, elseStmt, null); - ctx.replaceMe(accept(newIf)); + } else if (elseIsEmpty && thenExpr != null) { + // Convert "if (a()) {b()}" => "a()&&b()". + sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class, + "Replaced if statement with &&"); + + JsBinaryOperation op = new JsBinaryOperation(sourceInfo, + JsBinaryOperator.AND, x.getIfExpr(), thenExpr); + ctx.replaceMe(accept(op.makeStmt())); } else if (elseIsEmpty && elseStmt != null) { - /* - * If the else statement is present but has no effective statements, - * prune it - */ + // Convert "if (a()) {b()} else {}" => "if (a()) {b()}". sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class, "Pruned empty else statement"); - JsIf newIf = new JsIf(sourceInfo, x.getIfExpr(), thenStmt, null); - ctx.replaceMe(accept(newIf)); } } @@ -583,6 +601,26 @@ public static boolean exec(JsProgram program) { return (new JsStaticEval(program)).execImpl(); + } + + /** + * Attempts to extract a single expression from a given statement and returns + * it. If no such expression exists, returns <code>null</code>. + */ + protected static JsExpression extractExpression(JsStatement stmt) { + if (stmt == null) { + return null; + } + + if (stmt instanceof JsExprStmt) { + return ((JsExprStmt) stmt).getExpression(); + } + + if (stmt instanceof JsBlock && ((JsBlock) stmt).getStatements().size() == 1) { + return extractExpression(((JsBlock) stmt).getStatements().get(0)); + } + + return null; } protected static boolean isEmpty(JsStatement stmt) { Modified: trunk/dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java ============================================================================== --- trunk/dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (original) +++ trunk/dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java Thu Jun 11 12:08:45 2009 @@ -33,8 +33,13 @@ assertEquals("a();", optimize("if (a()) { }")); } + public void testIfWithEmptyThenAndElseExpression() throws Exception { + assertEquals("a()||b();", optimize("if (a()) { } else { b(); }")); + } + public void testIfWithEmptyThenAndElse() throws Exception { - assertEquals("if(!a()){b()}", optimize("if (a()) { } else { b(); }")); + assertEquals("if(!a()){throw 1}", + optimize("if (a()) { } else { throw 1; }")); } public void testIfWithEmptyThenAndEmptyElse() throws Exception { @@ -42,7 +47,21 @@ } public void testIfWithThenAndEmptyElse() throws Exception { - assertEquals("if(a()){b()}", optimize("if (a()) { b() } else { }")); + assertEquals("if(a()){throw 1}", optimize("if (a()) { throw 1; } else { }")); + } + + public void testIfWithThenExpressionAndEmptyElse() throws Exception { + assertEquals("a()&&b();", optimize("if (a()) { b() } else { }")); + } + + public void testIfWithThenExpressionAndElseExpression() throws Exception { + assertEquals("a()?b():c();", optimize("if (a()) { b() } else { c(); }")); + } + + public void testIfWithThenExpressionAndElseStatement() throws Exception { + // This can't be optimized further + assertEquals("if(a()){b()}else{throw 1}", + optimize("if (a()) { b() } else { throw 1; }")); } public void testLiteralEqNull() throws Exception { @@ -66,13 +85,13 @@ List<JsStatement> expected = JsParser.parse(SourceOrigin.UNKNOWN, program.getScope(), new StringReader(js)); program.getGlobalBlock().getStatements().addAll(expected); - + // Run the static evaluation over this new program JsStaticEval.exec(program); TextOutput text = new DefaultTextOutput(true); JsVisitor generator = new JsSourceGenerationVisitor(text); - + generator.accept(program); return text.toString(); } --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---