8025505: Constant folding deficiency

Provide constant folding of equality tests involving constant and null.

Reviewed-by: jjg
This commit is contained in:
Paul Govereau 2014-03-19 17:39:28 -04:00
parent e0bc15202b
commit 019025c61f
2 changed files with 144 additions and 8 deletions

View File

@ -2919,15 +2919,65 @@ public class Lower extends TreeTranslator {
// constant propagation would require that we take care to
// preserve possible side-effects in the condition expression.
// One common case is equality expressions involving a constant and null.
// Since null is not a constant expression (because null cannot be
// represented in the constant pool), equality checks involving null are
// not captured by Flow.isTrue/isFalse.
// Equality checks involving a constant and null, e.g.
// "" == null
// are safe to simplify as no side-effects can occur.
private boolean isTrue(JCTree exp) {
if (exp.type.isTrue())
return true;
Boolean b = expValue(exp);
return b == null ? false : b;
}
private boolean isFalse(JCTree exp) {
if (exp.type.isFalse())
return true;
Boolean b = expValue(exp);
return b == null ? false : !b;
}
/* look for (in)equality relations involving null.
* return true - if expression is always true
* false - if expression is always false
* null - if expression cannot be eliminated
*/
private Boolean expValue(JCTree exp) {
while (exp.hasTag(PARENS))
exp = ((JCParens)exp).expr;
boolean eq;
switch (exp.getTag()) {
case EQ: eq = true; break;
case NE: eq = false; break;
default:
return null;
}
// we have a JCBinary(EQ|NE)
// check if we have two literals (constants or null)
JCBinary b = (JCBinary)exp;
if (b.lhs.type.hasTag(BOT)) return expValueIsNull(eq, b.rhs);
if (b.rhs.type.hasTag(BOT)) return expValueIsNull(eq, b.lhs);
return null;
}
private Boolean expValueIsNull(boolean eq, JCTree t) {
if (t.type.hasTag(BOT)) return Boolean.valueOf(eq);
if (t.hasTag(LITERAL)) return Boolean.valueOf(!eq);
return null;
}
/** Visitor method for conditional expressions.
*/
@Override
public void visitConditional(JCConditional tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
if (isTrue(cond)) {
result = convert(translate(tree.truepart, tree.type), tree.type);
addPrunedInfo(cond);
} else if (cond.type.isFalse()) {
} else if (isFalse(cond)) {
result = convert(translate(tree.falsepart, tree.type), tree.type);
addPrunedInfo(cond);
} else {
@ -2951,10 +3001,10 @@ public class Lower extends TreeTranslator {
*/
public void visitIf(JCIf tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
if (isTrue(cond)) {
result = translate(tree.thenpart);
addPrunedInfo(cond);
} else if (cond.type.isFalse()) {
} else if (isFalse(cond)) {
if (tree.elsepart != null) {
result = translate(tree.elsepart);
} else {
@ -3333,21 +3383,21 @@ public class Lower extends TreeTranslator {
JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
switch (tree.getTag()) {
case OR:
if (lhs.type.isTrue()) {
if (isTrue(lhs)) {
result = lhs;
return;
}
if (lhs.type.isFalse()) {
if (isFalse(lhs)) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
case AND:
if (lhs.type.isFalse()) {
if (isFalse(lhs)) {
result = lhs;
return;
}
if (lhs.type.isTrue()) {
if (isTrue(lhs)) {
result = translate(tree.rhs, formals.tail.head);
return;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8025505
* @summary Constant folding deficiency
* @library /tools/javac/lib
* @build ToolBox
* @run main ConstFoldTest
*/
import java.net.URL;
import java.util.List;
public class ConstFoldTest {
public static void main(String... args) throws Exception {
new ConstFoldTest().run();
}
// This is the test case. This class should end up
// as straight-line code with no conditionals
class CFTest {
void m() {
int x;
if (1 != 2) x=1; else x=0;
if (1 == 2) x=1; else x=0;
if ("" != null) x=1; else x=0;
if ("" == null) x=1; else x=0;
if (null == null) x=1; else x=0;
if (null != null) x=1; else x=0;
x = 1 != 2 ? 1 : 0;
x = 1 == 2 ? 1 : 0;
x = "" != null ? 1 : 0;
x = "" == null ? 1 : 0;
x = null == null ? 1 : 0;
x = null != null ? 1 : 0;
boolean b;
b = 1 != 2 && true;
b = 1 == 2 || true;
b = ("" != null) && true;
b = ("" == null) || true;
b = (null == null) && true;
b = (null != null) || true;
}
}
// All of the conditionals above should be eliminated.
// these if* bytecodes should not be seen
final String regex = "\\sif(?:null|nonnull|eq|ne){1}\\s";
void run() throws Exception {
URL url = ConstFoldTest.class.getResource("ConstFoldTest$CFTest.class");
String result = ToolBox.javap(new ToolBox.JavaToolArgs().setAllArgs("-c", url.getFile()));
System.out.println(result);
List<String> bad_codes = ToolBox.grep(regex, result, "\n");
if (!bad_codes.isEmpty()) {
for (String code : bad_codes)
System.out.println("Bad OpCode Found: " + code);
throw new Exception("constant folding failed");
}
}
}