| /* |
| * Copyright 2008 Google Inc. |
| * |
| * 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 com.google.gwt.dev.jjs.test; |
| |
| import com.google.gwt.junit.client.GWTTestCase; |
| |
| /** |
| * Tests that static evaluation, mainly in |
| * {@link com.google.gwt.dev.jjs.impl.DeadCodeElimination DeadCodeElimination}, |
| * does not go wrong. |
| * |
| * This test does not verify that static evaluation is happening, merely that it |
| * does not make incorrect changes. To verify that static eval is happening, run |
| * with <code>-Dgwt.jjs.traceMethods=JStaticEvalTest.*</code> . All calls to |
| * assert should become trivial things like <code>assertEquals("", 5, 5)</code>. |
| * |
| * To verify the test itself, which includes a lot of random constants, run in |
| * hosted mode. |
| */ |
| public class JStaticEvalTest extends GWTTestCase { |
| private static void assertEquals(double expected, double actual) { |
| assertEquals(expected, actual, 0.0001); |
| } |
| |
| private volatile double fieldDoubleFive = 5.0; |
| private volatile boolean fieldFalse = false; |
| private volatile float fieldFloatFive = 5.0F; |
| private volatile int[] fieldIntArray = new int[10]; |
| private volatile int fieldIntFive = 5; |
| private volatile long fieldLongFive = 5L; |
| private volatile Object fieldObject = new Object(); |
| private volatile boolean fieldTrue = true; |
| |
| @Override |
| public String getModuleName() { |
| return "com.google.gwt.dev.jjs.CompilerSuite"; |
| } |
| |
| /** |
| * Tests simplifications on ternary conditional expressions. |
| */ |
| public void testConditionalExpressions() { |
| assertEquals(1, returnTrue() ? 1 : 2); |
| assertEquals(2, returnFalse() ? 1 : 2); |
| assertEquals(true, fieldTrue ? true : fieldFalse); |
| assertEquals(false, fieldTrue ? false : fieldTrue); |
| assertEquals(true, fieldTrue ? fieldTrue : false); |
| assertEquals(false, fieldTrue ? fieldFalse : true); |
| assertEquals(2, !fieldTrue ? 1 : 2); |
| assertEquals(2, !fieldTrue ? 1 : 2); |
| |
| /* |
| * This example causes Simplifier to recurse into itself, which in previous |
| * versions could cause a NullPointerException. The sequence of |
| * simplifications is: |
| */ |
| // (fieldFalse = false, !fieldFalse) ? 1 : 2 // inlining |
| // (fieldFalse = false, !fieldfalse ? 1 : 2) // move multi outward |
| // (fieldFalse = false, fieldFalse ? 2 : 1) // flip negative condition |
| int res = doSomethingAndReturnTrue() ? 1 : 2; |
| assertEquals(1, res); |
| } |
| |
| /** |
| * Test "true == booleanField" and permutations, as well as "true == false" |
| * and permutations. |
| */ |
| public void testEqualsBool() { |
| assertTrue(fieldTrue == returnTrue()); |
| assertTrue(returnTrue() == fieldTrue); |
| assertFalse(fieldTrue == returnFalse()); |
| assertFalse(returnFalse() == fieldTrue); |
| assertTrue(fieldTrue != returnFalse()); |
| assertTrue(returnFalse() != fieldTrue); |
| assertFalse(fieldTrue != returnTrue()); |
| assertFalse(returnTrue() != fieldTrue); |
| assertTrue(returnTrue() & returnTrue()); |
| assertTrue(returnTrue() | returnTrue()); |
| } |
| |
| /** |
| * Tests equality on literals. |
| */ |
| public void testEqualsLit() { |
| assertTrue(returnTrue() == returnTrue()); |
| assertFalse(returnTrue() == returnFalse()); |
| assertFalse(returnFalse() == returnTrue()); |
| assertTrue(returnFalse() == returnFalse()); |
| assertFalse(returnTrue() != returnTrue()); |
| assertTrue(returnTrue() != returnFalse()); |
| assertTrue(returnFalse() != returnTrue()); |
| assertFalse(returnFalse() != returnFalse()); |
| |
| assertTrue(returnIntFive() == returnIntFive()); |
| assertFalse(returnIntFive() != returnIntFive()); |
| assertTrue(returnDoubleOneHalf() == returnDoubleOneHalf()); |
| assertFalse(returnDoubleOneHalf() != returnDoubleOneHalf()); |
| } |
| |
| /** |
| * Test rewriting if (!x) a else b to if(x) b else a. Likewise for conditional |
| * expressions. |
| */ |
| public void testFlippedIf() { |
| String branch; |
| if (!fieldTrue) { |
| branch = "A"; |
| } else { |
| branch = "B"; |
| } |
| assertEquals("B", branch); |
| assertEquals("B", !fieldTrue ? "A" : "B"); |
| } |
| |
| /** |
| * Tests constant folding. |
| */ |
| public void testOpsOnLiterals() { |
| assertEquals(10, returnIntFive() + returnIntFive()); |
| assertEquals(0, returnIntFive() - returnIntFive()); |
| assertEquals(25, returnIntFive() * returnIntFive()); |
| assertEquals(1, returnIntFive() / returnIntFive()); |
| assertEquals(3, returnIntThree() % returnIntFive()); |
| assertEquals(96, returnIntThree() << returnIntFive()); |
| assertEquals(0, returnIntThree() >> returnIntFive()); |
| assertEquals(134217727, (-returnIntThree()) >>> returnIntFive()); |
| assertEquals(7, returnIntFive() | returnIntThree()); |
| assertEquals(1, returnIntFive() & returnIntThree()); |
| assertEquals(0, returnIntFive() ^ returnIntFive()); |
| |
| assertEquals(1.0, returnDoubleOneHalf() + returnDoubleOneHalf()); |
| assertEquals(0.0, returnDoubleOneHalf() - returnDoubleOneHalf()); |
| assertEquals(0.25, returnDoubleOneHalf() * returnDoubleOneHalf()); |
| assertEquals(1.0, returnDoubleOneHalf() / returnDoubleOneHalf()); |
| assertEquals(0.5, returnDoubleOneHalf() % returnDoubleFive()); |
| |
| assertTrue(returnIntFive() == returnIntFive()); |
| assertTrue(returnLongFive() == returnLongFive()); |
| assertTrue(returnFloatFive() == returnFloatFive()); |
| assertTrue(returnDoubleFive() == returnDoubleFive()); |
| assertTrue(returnCharFive() == returnCharFive()); |
| assertTrue(returnIntFive() == returnFloatFive()); |
| |
| assertFalse(returnIntFive() != returnIntFive()); |
| assertFalse(returnLongFive() != returnLongFive()); |
| assertFalse(returnFloatFive() != returnFloatFive()); |
| assertFalse(returnDoubleFive() != returnDoubleFive()); |
| assertFalse(returnCharFive() != returnCharFive()); |
| assertFalse(returnIntFive() != returnFloatFive()); |
| |
| assertTrue(returnTrue() || returnFalse()); |
| assertFalse(returnTrue() && returnFalse()); |
| assertFalse(returnTrue() ^ returnTrue()); |
| |
| assertFalse(returnIntFive() < returnIntThree()); |
| assertFalse(returnIntFive() <= returnIntThree()); |
| assertTrue(returnIntFive() > returnIntThree()); |
| assertTrue(returnIntFive() >= returnIntThree()); |
| |
| assertTrue(returnDoubleOneHalf() < returnDoubleFive()); |
| assertTrue(returnDoubleOneHalf() <= returnDoubleFive()); |
| assertFalse(returnDoubleOneHalf() > returnDoubleFive()); |
| assertFalse(returnDoubleOneHalf() >= returnDoubleFive()); |
| |
| assertEquals(10, returnIntFive() + returnCharFive()); |
| assertTrue(returnIntThree() < returnCharFive()); |
| |
| assertEquals(-5, -returnIntFive()); |
| assertEquals(-5L, -returnLongFive()); |
| assertEquals(-5.0, -returnFloatFive()); |
| assertEquals(-5.0, -returnDoubleFive()); |
| assertEquals(-10000000000000000000.0, -returnBigDouble()); |
| |
| assertFalse(!returnTrue()); |
| assertTrue(!returnFalse()); |
| |
| assertEquals(-6, ~returnIntFive()); |
| assertEquals(-6L, ~returnLongFive()); |
| |
| assertEquals(65536, ((char) returnIntNegOne()) + 1); |
| assertEquals(10.0, ((double) returnIntFive()) + ((double) returnIntFive())); |
| assertEquals(1.5, returnFloatOneHalf() + 1); |
| } |
| |
| /** |
| * Test various useless operations like x+0 and x*1. |
| */ |
| public void testUselessOps() { |
| assertEquals(5, fieldIntFive + returnIntZero()); |
| assertEquals(5L, fieldLongFive + returnIntZero()); |
| assertEquals(5.0, fieldFloatFive + returnIntZero()); |
| assertEquals(5.0, fieldDoubleFive + returnIntZero()); |
| assertEquals(5.0, fieldDoubleFive + returnCharZero()); |
| |
| assertEquals(5, returnIntZero() + fieldIntFive); |
| assertEquals(5L, returnIntZero() + fieldLongFive); |
| assertEquals(5.0, returnIntZero() + fieldFloatFive); |
| assertEquals(5.0, returnIntZero() + fieldDoubleFive); |
| assertEquals(5.0, returnCharZero() + fieldDoubleFive); |
| |
| assertEquals(5, fieldIntFive - returnIntZero()); |
| assertEquals(5L, fieldLongFive - returnIntZero()); |
| assertEquals(5.0, fieldFloatFive - returnIntZero()); |
| assertEquals(5.0, fieldDoubleFive - returnIntZero()); |
| |
| assertEquals(-5, returnIntZero() - fieldIntFive); |
| assertEquals(-5L, returnIntZero() - fieldLongFive); |
| assertEquals(-5.0, returnDoubleZero() - fieldLongFive); |
| assertEquals(-5.0, returnIntZero() - fieldFloatFive); |
| assertEquals(-5.0, returnIntZero() - fieldDoubleFive); |
| |
| assertEquals(5, fieldIntFive * returnIntOne()); |
| assertEquals(5L, fieldLongFive * returnLongOne()); |
| assertEquals(5.0, fieldFloatFive * returnFloatOne()); |
| assertEquals(5.0, fieldDoubleFive * returnDoubleOne()); |
| |
| assertEquals(5, fieldIntFive / returnIntOne()); |
| assertEquals(5L, fieldLongFive / returnLongOne()); |
| assertEquals(5.0, fieldFloatFive / returnFloatOne()); |
| assertEquals(5.0, fieldDoubleFive / returnDoubleOne()); |
| |
| assertEquals(-5, fieldIntFive * -returnIntOne()); |
| assertEquals(-5L, fieldLongFive * -returnLongOne()); |
| assertEquals(-5.0, fieldFloatFive * -returnFloatOne()); |
| assertEquals(-5.0, fieldDoubleFive * -returnDoubleOne()); |
| assertEquals(-327675, fieldIntFive * -returnCharNegOne()); |
| |
| assertEquals(-5, fieldIntFive / -returnIntOne()); |
| assertEquals(-5L, fieldLongFive / -returnLongOne()); |
| assertEquals(-5.0, fieldFloatFive / -returnFloatOne()); |
| assertEquals(-5.0, fieldDoubleFive / -returnDoubleOne()); |
| |
| assertEquals(5, -returnMinusFieldIntFive()); |
| assertEquals(5L, -returnMinusFieldLongFive()); |
| assertEquals(5.0, -returnMinusFieldFloatFive()); |
| assertEquals(5.0, -returnMinusFieldDoubleFive()); |
| |
| assertEquals(5, fieldIntFive << returnIntZero()); |
| assertEquals(5L, fieldLongFive << returnIntZero()); |
| |
| assertEquals(5, fieldIntFive >> returnIntZero()); |
| assertEquals(5L, fieldLongFive >> returnIntZero()); |
| |
| assertEquals(5, fieldIntFive >>> returnIntZero()); |
| assertEquals(5L, fieldLongFive >>> returnIntZero()); |
| |
| assertTrue(!returnNotFieldTrue()); |
| |
| assertTrue(fieldTrue ^ returnFalse()); |
| assertFalse(fieldTrue ^ returnTrue()); |
| assertFalse(returnTrue() ^ fieldTrue); |
| assertTrue(returnFalse() ^ fieldTrue); |
| |
| assertEquals(0.0, fieldIntFive * returnDoubleZero()); |
| |
| // do not simplify x*0 if x has a side effect |
| try { |
| assertEquals(0.0, throwError() * returnDoubleZero()); |
| fail("Expected an exception"); |
| } catch (Error e) { |
| } |
| |
| assertEquals(0.0, returnDoubleZero() * fieldIntFive); |
| |
| // do not simplify 0*x if x has a side effect |
| try { |
| assertEquals(0.0, returnDoubleZero() * throwError()); |
| fail("Expected an exception"); |
| } catch (Error e) { |
| } |
| |
| assertTrue(fieldIntArray != null); |
| assertFalse(fieldIntArray == null); |
| if (fieldIntArray == null) { |
| fail(); |
| } |
| if (fieldIntArray != null) { |
| } else { |
| fail(); |
| } |
| |
| // do not simplify foo==null if foo can be a string |
| assertTrue(returnEmptyString() != null); |
| assertFalse(returnEmptyString() == null); |
| if (returnEmptyString() == null) { |
| fail(); |
| } |
| assertFalse(fieldObject == null); |
| if (fieldObject == null) { |
| fail(); |
| } |
| } |
| |
| /** |
| * This method will inline as a multi. |
| */ |
| private boolean doSomethingAndReturnTrue() { |
| fieldTrue = true; |
| return !fieldFalse; |
| } |
| |
| // All of these returnFoo() methods exist so that the |
| // JDT will not be able to statically evaluate with |
| // the returned values. These simple methods will be |
| // inlined by GWT, though, thus giving its static |
| // evaluation a chance to run. |
| |
| /** |
| * Return a double too large to fit in a long. |
| */ |
| private double returnBigDouble() { |
| return 10000000000000000000.0; |
| } |
| |
| private char returnCharFive() { |
| return (char) 5; |
| } |
| |
| private char returnCharNegOne() { |
| return (char) -1; |
| } |
| |
| private char returnCharZero() { |
| return (char) 0; |
| } |
| |
| private double returnDoubleFive() { |
| return 5.0; |
| } |
| |
| private double returnDoubleOne() { |
| return 1.0; |
| } |
| |
| private double returnDoubleOneHalf() { |
| return 0.5; |
| } |
| |
| private double returnDoubleZero() { |
| return 0.0; |
| } |
| |
| private String returnEmptyString() { |
| return ""; |
| } |
| |
| private boolean returnFalse() { |
| return false; |
| } |
| |
| private float returnFloatFive() { |
| return 5.0F; |
| } |
| |
| private float returnFloatOne() { |
| return 1.0F; |
| } |
| |
| private float returnFloatOneHalf() { |
| return 0.5F; |
| } |
| |
| private int returnIntFive() { |
| return 5; |
| } |
| |
| private int returnIntNegOne() { |
| return -1; |
| } |
| |
| private int returnIntOne() { |
| return 1; |
| } |
| |
| private int returnIntThree() { |
| return 3; |
| } |
| |
| private int returnIntZero() { |
| return 0; |
| } |
| |
| private long returnLongFive() { |
| return 5L; |
| } |
| |
| private long returnLongOne() { |
| return 1L; |
| } |
| |
| private double returnMinusFieldDoubleFive() { |
| return -fieldDoubleFive; |
| } |
| |
| private float returnMinusFieldFloatFive() { |
| return -fieldFloatFive; |
| } |
| |
| private int returnMinusFieldIntFive() { |
| return -fieldIntFive; |
| } |
| |
| private long returnMinusFieldLongFive() { |
| return -fieldLongFive; |
| } |
| |
| private boolean returnNotFieldTrue() { |
| return !fieldTrue; |
| } |
| |
| private boolean returnTrue() { |
| return true; |
| } |
| |
| private int throwError() { |
| throw new Error(); |
| } |
| } |