blob: e96578a8d7460ce589b53342789e6c8473fa1d06 [file] [log] [blame]
/*
* 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();
}
}