[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
On Tue, Jun 9, 2009 at 11:01 AM, Matt Mastraccimatt...@mastracci.com wrote: Yeah... I would love to have a single AST to represent both of the language states - many optimizations don't happen because we toss all the Java type info during the conversion to JS. For instance, you can't safely optimize this: if (blah != null) to this: if (blah) without knowing what type blah was at the beginning. I expect this would work well, too. In addition, a lot of optimizations would be a lot simpler to write (and some would just fall out of that structure) if we were dealing with a more abstract SSA version of the code, rather than a more direct AST. To be precise, I think what you're getting at is that within-method data flow would be helpful to represent. It's safer to stay with an AST representation due to the fact that the GWT compiler must output valid JavaScript syntax, and in particular does not have the luxury of using any kind of goto. However, it could certainly use an AST but either have the AST follow the SSA invariant, or else augment the AST with a data-flow graph. Either way, the goal is to get data flow information in there, so that silly code like (x=10,x) can be replaced by simply 10. -Lex --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
LGTM. Want to point out that we can optimize some of these even better in cases where the nested code is an expression statement. http://gwt-code-reviews.appspot.com/33845/diff/1/2 File dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (right): http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode37 Line 37: assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); a()||b() http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode45 Line 45: assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); a()b() http://gwt-code-reviews.appspot.com/33845 --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
SGTM. I'll start a new review with the remainder of the changes. On 10-Jun-09, at 2:16 PM, Scott Blum wrote: I thought I'd go ahead and commit what you have so far, if you don't object? On Wed, Jun 10, 2009 at 4:12 PM, mmastrac.altern...@gmail.com wrote: I'll update the patch with this change. While I'm at it, I may as well tackle this one too: if (test) {a()} else {b()} - test?a():b() On 2009/06/10 19:56:18, scottb wrote: LGTM. Want to point out that we can optimize some of these even better in cases where the nested code is an expression statement. http://gwt-code-reviews.appspot.com/33845/diff/1/2 File dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (right): http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode37 Line 37: assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); a()||b() http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode45 Line 45: assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); a()b() http://gwt-code-reviews.appspot.com/33845 --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
Scott, do you mean replacing if(a != null) { expr; } with a expr? -Ray On Thu, Jun 11, 2009 at 4:56 AM, sco...@google.com wrote: LGTM. Want to point out that we can optimize some of these even better in cases where the nested code is an expression statement. http://gwt-code-reviews.appspot.com/33845/diff/1/2 File dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (right): http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode37 Line 37: assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); a()||b() http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode45 Line 45: assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); a()b() http://gwt-code-reviews.appspot.com/33845 --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
Ultimately that'd be great, whether that's a one step operation or a two-step. On Wed, Jun 10, 2009 at 7:16 PM, Ray Cromwell cromwell...@gmail.com wrote: Scott, do you mean replacing if(a != null) { expr; } with a expr? -Ray On Thu, Jun 11, 2009 at 4:56 AM, sco...@google.com wrote: LGTM. Want to point out that we can optimize some of these even better in cases where the nested code is an expression statement. http://gwt-code-reviews.appspot.com/33845/diff/1/2 File dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (right): http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode37 Line 37: assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); a()||b() http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode45 Line 45: assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); a()b() http://gwt-code-reviews.appspot.com/33845 --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
After I sent that message, I peeked into EqualityNormalizer which is basically pre-munging all the equality operators that compare against null to Cast.isNull() and Cast.isNotNull() as I described below. On 10-Jun-09, at 8:16 PM, Matt Mastracci wrote: That construct isn't a generically safe JS optimization, unless you have additional type info at the JS level to tell you what Java type the ifExpr was. I don't know for sure whether that information is available after the transition to JS (does SOYC make this available?). I believe that GenerateJavaScriptAST could be a bit smarter and not generate == null and != null for binary equality ops where the operand is known to be a reference type that isn't a string. One example failure case where null equality is not equivalent to binary coersion is the following: var a = false; if (a != null) { alert('blah'); } and var a = false; a alert('blah') BTW, this quick test shows that the problematic values are 0 (numeric zero), (the empty string), NaN and false: table script tests = [ [], {}, 0, null, undefined, , 0, null, undefined, NaN, NaN, true, false ] for (i = 0; i tests.length; i++) { document.write(trtd + ( + tests[i]) + /tdtd + (! tests[i]) + /tdtd + (tests[i] == null) + /td/tr); } /script On 10-Jun-09, at 5:20 PM, Scott Blum wrote: Ultimately that'd be great, whether that's a one step operation or a two-step. On Wed, Jun 10, 2009 at 7:16 PM, Ray Cromwell cromwell...@gmail.com wrote: Scott, do you mean replacing if(a != null) { expr; } with a expr? -Ray On Thu, Jun 11, 2009 at 4:56 AM, sco...@google.com wrote: LGTM. Want to point out that we can optimize some of these even better in cases where the nested code is an expression statement. http://gwt-code-reviews.appspot.com/33845/diff/1/2 File dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (right): http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode37 Line 37: assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); a()||b() http://gwt-code-reviews.appspot.com/33845/diff/1/2#newcode45 Line 45: assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); a()b() http://gwt-code-reviews.appspot.com/33845 --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
This brings up the issue of whether or not there isn't someway to abstract some of these optimizations on the ASTs so that they can be shared by the Java and JS optimizers. I made patch along the same lines to the simplifier mirroring the Java simplifier. It seems like a lot of optimizations are being duplicated. -Ray On Tue, Jun 9, 2009 at 1:12 AM, mmastrac.altern...@gmail.com wrote: Reviewers: scottb, Description: I'm tackling another small issue on the JS side to get myself up to speed with the code (esp. the SOYC changes throughout) and help shake out all the cobwebs since my last set of patches :). This is a simple patch to improve the optimization of if statements. These items show up in compiled output, mostly in the generated exception handler code. It adds two extra optimizations: - Empty, but present else statements are pruned: if (x) {doSomething();} else {} - if (x) {doSomething();} - If statements with empty then conditions are inverted: if (x) {} else {doSomething()} - if (!x) {doSomething();} I also cleaned up my previous set of unit tests to use the clearer assertEquals() instead of assertTrue(x.equals(...)). Please review this at http://gwt-code-reviews.appspot.com/33845 Affected files: dev/core/src/com/google/gwt/dev/js/JsStaticEval.java dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java Index: dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java === --- dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (revision 5519) +++ dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (working copy) @@ -29,20 +29,36 @@ public class JsStaticEvalTest extends TestCase { + public void testIfWithEmptyThen() throws Exception { + assertEquals(a();, optimize(if (a()) { })); + } + + public void testIfWithEmptyThenAndElse() throws Exception { + assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); + } + + public void testIfWithEmptyThenAndEmptyElse() throws Exception { + assertEquals(a();, optimize(if (a()) { } else { })); + } + + public void testIfWithThenAndEmptyElse() throws Exception { + assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); + } + public void testLiteralEqNull() throws Exception { - assertTrue(optimize(alert('test' == null)).equals(alert(false);)); + assertEquals(alert(false);, optimize(alert('test' == null))); } public void testLiteralNeNull() throws Exception { - assertTrue(optimize(alert('test' != null)).equals(alert(true);)); + assertEquals(alert(true);, optimize(alert('test' != null))); } public void testNullEqNull() throws Exception { - assertTrue(optimize(alert(null == null)).equals(alert(true);)); + assertEquals(alert(true);, optimize(alert(null == null))); } public void testNullNeNull() throws Exception { - assertTrue(optimize(alert(null != null)).equals(alert(false);)); + assertEquals(alert(false);, optimize(alert(null != null))); } private String optimize(String js) throws Exception { Index: dev/core/src/com/google/gwt/dev/js/JsStaticEval.java === --- dev/core/src/com/google/gwt/dev/js/JsStaticEval.java (revision 5519) +++ dev/core/src/com/google/gwt/dev/js/JsStaticEval.java (working copy) @@ -35,6 +35,7 @@ import com.google.gwt.dev.js.ast.JsPrefixOperation; import com.google.gwt.dev.js.ast.JsProgram; import com.google.gwt.dev.js.ast.JsStatement; +import com.google.gwt.dev.js.ast.JsUnaryOperation; import com.google.gwt.dev.js.ast.JsUnaryOperator; import com.google.gwt.dev.js.ast.JsValueLiteral; import com.google.gwt.dev.js.ast.JsVars; @@ -348,8 +349,37 @@ block.getStatements().add(decls); } ctx.replaceMe(accept(block)); - } else if (isEmpty(thenStmt) isEmpty(elseStmt)) { - ctx.replaceMe(expr.makeStmt()); + } else { + boolean thenIsEmpty = isEmpty(thenStmt); + boolean elseIsEmpty = isEmpty(elseStmt); + + if (thenIsEmpty elseIsEmpty) { + ctx.replaceMe(expr.makeStmt()); + } else if (thenIsEmpty !elseIsEmpty) { + /* + * If the then block is blank, but the else statement has statements, + * invert the test + */ + 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 elseStmt != null) { + /* + * If the else statement is present but has no effective statements, + *
[gwt-contrib] Re: More if-statement optimizations in JsStaticEval
Yeah... I would love to have a single AST to represent both of the language states - many optimizations don't happen because we toss all the Java type info during the conversion to JS. For instance, you can't safely optimize this: if (blah != null) to this: if (blah) without knowing what type blah was at the beginning. In addition, a lot of optimizations would be a lot simpler to write (and some would just fall out of that structure) if we were dealing with a more abstract SSA version of the code, rather than a more direct AST. On 9-Jun-09, at 5:40 AM, Ray Cromwell wrote: This brings up the issue of whether or not there isn't someway to abstract some of these optimizations on the ASTs so that they can be shared by the Java and JS optimizers. I made patch along the same lines to the simplifier mirroring the Java simplifier. It seems like a lot of optimizations are being duplicated. -Ray On Tue, Jun 9, 2009 at 1:12 AM, mmastrac.altern...@gmail.com wrote: Reviewers: scottb, Description: I'm tackling another small issue on the JS side to get myself up to speed with the code (esp. the SOYC changes throughout) and help shake out all the cobwebs since my last set of patches :). This is a simple patch to improve the optimization of if statements. These items show up in compiled output, mostly in the generated exception handler code. It adds two extra optimizations: - Empty, but present else statements are pruned: if (x) {doSomething();} else {} - if (x) {doSomething();} - If statements with empty then conditions are inverted: if (x) {} else {doSomething()} - if (!x) {doSomething();} I also cleaned up my previous set of unit tests to use the clearer assertEquals() instead of assertTrue(x.equals(...)). Please review this at http://gwt-code-reviews.appspot.com/33845 Affected files: dev/core/src/com/google/gwt/dev/js/JsStaticEval.java dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java Index: dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java === --- dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (revision 5519) +++ dev/core/test/com/google/gwt/dev/js/JsStaticEvalTest.java (working copy) @@ -29,20 +29,36 @@ public class JsStaticEvalTest extends TestCase { + public void testIfWithEmptyThen() throws Exception { +assertEquals(a();, optimize(if (a()) { })); + } + + public void testIfWithEmptyThenAndElse() throws Exception { +assertEquals(if(!a()){b()}, optimize(if (a()) { } else { b(); })); + } + + public void testIfWithEmptyThenAndEmptyElse() throws Exception { +assertEquals(a();, optimize(if (a()) { } else { })); + } + + public void testIfWithThenAndEmptyElse() throws Exception { +assertEquals(if(a()){b()}, optimize(if (a()) { b() } else { })); + } + public void testLiteralEqNull() throws Exception { -assertTrue(optimize(alert('test' == null)).equals(alert(false);)); +assertEquals(alert(false);, optimize(alert('test' == null))); } public void testLiteralNeNull() throws Exception { -assertTrue(optimize(alert('test' != null)).equals(alert(true);)); +assertEquals(alert(true);, optimize(alert('test' != null))); } public void testNullEqNull() throws Exception { -assertTrue(optimize(alert(null == null)).equals(alert(true);)); +assertEquals(alert(true);, optimize(alert(null == null))); } public void testNullNeNull() throws Exception { -assertTrue(optimize(alert(null != null)).equals(alert(false);)); +assertEquals(alert(false);, optimize(alert(null != null))); } private String optimize(String js) throws Exception { Index: dev/core/src/com/google/gwt/dev/js/JsStaticEval.java === --- dev/core/src/com/google/gwt/dev/js/JsStaticEval.java (revision 5519) +++ dev/core/src/com/google/gwt/dev/js/JsStaticEval.java (working copy) @@ -35,6 +35,7 @@ import com.google.gwt.dev.js.ast.JsPrefixOperation; import com.google.gwt.dev.js.ast.JsProgram; import com.google.gwt.dev.js.ast.JsStatement; +import com.google.gwt.dev.js.ast.JsUnaryOperation; import com.google.gwt.dev.js.ast.JsUnaryOperator; import com.google.gwt.dev.js.ast.JsValueLiteral; import com.google.gwt.dev.js.ast.JsVars; @@ -348,8 +349,37 @@ block.getStatements().add(decls); } ctx.replaceMe(accept(block)); - } else if (isEmpty(thenStmt) isEmpty(elseStmt)) { -ctx.replaceMe(expr.makeStmt()); + } else { +boolean thenIsEmpty = isEmpty(thenStmt); +boolean elseIsEmpty = isEmpty(elseStmt); + +if (thenIsEmpty elseIsEmpty) { + ctx.replaceMe(expr.makeStmt()); +} else if (thenIsEmpty !elseIsEmpty) { + /* + * If the then block is blank, but the else