author | pgovereau |
Wed, 19 Mar 2014 17:39:28 -0400 | |
changeset 23791 | f1cdccbc1040 |
parent 23790 | 0697e38017ec |
child 23792 | eabe3e8a29bf |
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Wed Mar 19 11:34:27 2014 -0400 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Wed Mar 19 17:39:28 2014 -0400 @@ -2919,15 +2919,65 @@ // 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 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 @@ 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; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/ConstFoldTest.java Wed Mar 19 17:39:28 2014 -0400 @@ -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"); + } + } +}