--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java Sun Aug 17 15:52:32 2014 +0100
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 1999, 2013, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.jvm.*;
+import com.sun.tools.javac.util.*;
+
+import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
+
+import static com.sun.tools.javac.jvm.ByteCodes.*;
+
+/** Helper class for constant folding, used by the attribution phase.
+ * This class is marked strictfp as mandated by JLS 15.4.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+strictfp class ConstFold {
+ protected static final Context.Key<ConstFold> constFoldKey = new Context.Key<>();
+
+ private Symtab syms;
+
+ public static ConstFold instance(Context context) {
+ ConstFold instance = context.get(constFoldKey);
+ if (instance == null)
+ instance = new ConstFold(context);
+ return instance;
+ }
+
+ private ConstFold(Context context) {
+ context.put(constFoldKey, this);
+
+ syms = Symtab.instance(context);
+ }
+
+ static final Integer minusOne = -1;
+ static final Integer zero = 0;
+ static final Integer one = 1;
+
+ /** Convert boolean to integer (true = 1, false = 0).
+ */
+ private static Integer b2i(boolean b) {
+ return b ? one : zero;
+ }
+ private static int intValue(Object x) { return ((Number)x).intValue(); }
+ private static long longValue(Object x) { return ((Number)x).longValue(); }
+ private static float floatValue(Object x) { return ((Number)x).floatValue(); }
+ private static double doubleValue(Object x) { return ((Number)x).doubleValue(); }
+
+ /** Fold binary or unary operation, returning constant type reflecting the
+ * operations result. Return null if fold failed due to an
+ * arithmetic exception.
+ * @param opcode The operation's opcode instruction (usually a byte code),
+ * as entered by class Symtab.
+ * @param argtypes The operation's argument types (a list of length 1 or 2).
+ * Argument types are assumed to have non-null constValue's.
+ */
+ Type fold(int opcode, List<Type> argtypes) {
+ int argCount = argtypes.length();
+ if (argCount == 1)
+ return fold1(opcode, argtypes.head);
+ else if (argCount == 2)
+ return fold2(opcode, argtypes.head, argtypes.tail.head);
+ else
+ throw new AssertionError();
+ }
+
+ /** Fold unary operation.
+ * @param opcode The operation's opcode instruction (usually a byte code),
+ * as entered by class Symtab.
+ * opcode's ifeq to ifge are for postprocessing
+ * xcmp; ifxx pairs of instructions.
+ * @param operand The operation's operand type.
+ * Argument types are assumed to have non-null constValue's.
+ */
+ Type fold1(int opcode, Type operand) {
+ try {
+ Object od = operand.constValue();
+ switch (opcode) {
+ case nop:
+ return operand;
+ case ineg: // unary -
+ return syms.intType.constType(-intValue(od));
+ case ixor: // ~
+ return syms.intType.constType(~intValue(od));
+ case bool_not: // !
+ return syms.booleanType.constType(b2i(intValue(od) == 0));
+ case ifeq:
+ return syms.booleanType.constType(b2i(intValue(od) == 0));
+ case ifne:
+ return syms.booleanType.constType(b2i(intValue(od) != 0));
+ case iflt:
+ return syms.booleanType.constType(b2i(intValue(od) < 0));
+ case ifgt:
+ return syms.booleanType.constType(b2i(intValue(od) > 0));
+ case ifle:
+ return syms.booleanType.constType(b2i(intValue(od) <= 0));
+ case ifge:
+ return syms.booleanType.constType(b2i(intValue(od) >= 0));
+
+ case lneg: // unary -
+ return syms.longType.constType(new Long(-longValue(od)));
+ case lxor: // ~
+ return syms.longType.constType(new Long(~longValue(od)));
+
+ case fneg: // unary -
+ return syms.floatType.constType(new Float(-floatValue(od)));
+
+ case dneg: // ~
+ return syms.doubleType.constType(new Double(-doubleValue(od)));
+
+ default:
+ return null;
+ }
+ } catch (ArithmeticException e) {
+ return null;
+ }
+ }
+
+ /** Fold binary operation.
+ * @param opcode The operation's opcode instruction (usually a byte code),
+ * as entered by class Symtab.
+ * opcode's ifeq to ifge are for postprocessing
+ * xcmp; ifxx pairs of instructions.
+ * @param left The type of the operation's left operand.
+ * @param right The type of the operation's right operand.
+ */
+ Type fold2(int opcode, Type left, Type right) {
+ try {
+ if (opcode > ByteCodes.preMask) {
+ // we are seeing a composite instruction of the form xcmp; ifxx.
+ // In this case fold both instructions separately.
+ Type t1 = fold2(opcode >> ByteCodes.preShift, left, right);
+ return (t1.constValue() == null) ? t1
+ : fold1(opcode & ByteCodes.preMask, t1);
+ } else {
+ Object l = left.constValue();
+ Object r = right.constValue();
+ switch (opcode) {
+ case iadd:
+ return syms.intType.constType(intValue(l) + intValue(r));
+ case isub:
+ return syms.intType.constType(intValue(l) - intValue(r));
+ case imul:
+ return syms.intType.constType(intValue(l) * intValue(r));
+ case idiv:
+ return syms.intType.constType(intValue(l) / intValue(r));
+ case imod:
+ return syms.intType.constType(intValue(l) % intValue(r));
+ case iand:
+ return (left.hasTag(BOOLEAN)
+ ? syms.booleanType : syms.intType)
+ .constType(intValue(l) & intValue(r));
+ case bool_and:
+ return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0));
+ case ior:
+ return (left.hasTag(BOOLEAN)
+ ? syms.booleanType : syms.intType)
+ .constType(intValue(l) | intValue(r));
+ case bool_or:
+ return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0));
+ case ixor:
+ return (left.hasTag(BOOLEAN)
+ ? syms.booleanType : syms.intType)
+ .constType(intValue(l) ^ intValue(r));
+ case ishl: case ishll:
+ return syms.intType.constType(intValue(l) << intValue(r));
+ case ishr: case ishrl:
+ return syms.intType.constType(intValue(l) >> intValue(r));
+ case iushr: case iushrl:
+ return syms.intType.constType(intValue(l) >>> intValue(r));
+ case if_icmpeq:
+ return syms.booleanType.constType(
+ b2i(intValue(l) == intValue(r)));
+ case if_icmpne:
+ return syms.booleanType.constType(
+ b2i(intValue(l) != intValue(r)));
+ case if_icmplt:
+ return syms.booleanType.constType(
+ b2i(intValue(l) < intValue(r)));
+ case if_icmpgt:
+ return syms.booleanType.constType(
+ b2i(intValue(l) > intValue(r)));
+ case if_icmple:
+ return syms.booleanType.constType(
+ b2i(intValue(l) <= intValue(r)));
+ case if_icmpge:
+ return syms.booleanType.constType(
+ b2i(intValue(l) >= intValue(r)));
+
+ case ladd:
+ return syms.longType.constType(
+ new Long(longValue(l) + longValue(r)));
+ case lsub:
+ return syms.longType.constType(
+ new Long(longValue(l) - longValue(r)));
+ case lmul:
+ return syms.longType.constType(
+ new Long(longValue(l) * longValue(r)));
+ case ldiv:
+ return syms.longType.constType(
+ new Long(longValue(l) / longValue(r)));
+ case lmod:
+ return syms.longType.constType(
+ new Long(longValue(l) % longValue(r)));
+ case land:
+ return syms.longType.constType(
+ new Long(longValue(l) & longValue(r)));
+ case lor:
+ return syms.longType.constType(
+ new Long(longValue(l) | longValue(r)));
+ case lxor:
+ return syms.longType.constType(
+ new Long(longValue(l) ^ longValue(r)));
+ case lshl: case lshll:
+ return syms.longType.constType(
+ new Long(longValue(l) << intValue(r)));
+ case lshr: case lshrl:
+ return syms.longType.constType(
+ new Long(longValue(l) >> intValue(r)));
+ case lushr:
+ return syms.longType.constType(
+ new Long(longValue(l) >>> intValue(r)));
+ case lcmp:
+ if (longValue(l) < longValue(r))
+ return syms.intType.constType(minusOne);
+ else if (longValue(l) > longValue(r))
+ return syms.intType.constType(one);
+ else
+ return syms.intType.constType(zero);
+ case fadd:
+ return syms.floatType.constType(
+ new Float(floatValue(l) + floatValue(r)));
+ case fsub:
+ return syms.floatType.constType(
+ new Float(floatValue(l) - floatValue(r)));
+ case fmul:
+ return syms.floatType.constType(
+ new Float(floatValue(l) * floatValue(r)));
+ case fdiv:
+ return syms.floatType.constType(
+ new Float(floatValue(l) / floatValue(r)));
+ case fmod:
+ return syms.floatType.constType(
+ new Float(floatValue(l) % floatValue(r)));
+ case fcmpg: case fcmpl:
+ if (floatValue(l) < floatValue(r))
+ return syms.intType.constType(minusOne);
+ else if (floatValue(l) > floatValue(r))
+ return syms.intType.constType(one);
+ else if (floatValue(l) == floatValue(r))
+ return syms.intType.constType(zero);
+ else if (opcode == fcmpg)
+ return syms.intType.constType(one);
+ else
+ return syms.intType.constType(minusOne);
+ case dadd:
+ return syms.doubleType.constType(
+ new Double(doubleValue(l) + doubleValue(r)));
+ case dsub:
+ return syms.doubleType.constType(
+ new Double(doubleValue(l) - doubleValue(r)));
+ case dmul:
+ return syms.doubleType.constType(
+ new Double(doubleValue(l) * doubleValue(r)));
+ case ddiv:
+ return syms.doubleType.constType(
+ new Double(doubleValue(l) / doubleValue(r)));
+ case dmod:
+ return syms.doubleType.constType(
+ new Double(doubleValue(l) % doubleValue(r)));
+ case dcmpg: case dcmpl:
+ if (doubleValue(l) < doubleValue(r))
+ return syms.intType.constType(minusOne);
+ else if (doubleValue(l) > doubleValue(r))
+ return syms.intType.constType(one);
+ else if (doubleValue(l) == doubleValue(r))
+ return syms.intType.constType(zero);
+ else if (opcode == dcmpg)
+ return syms.intType.constType(one);
+ else
+ return syms.intType.constType(minusOne);
+ case if_acmpeq:
+ return syms.booleanType.constType(b2i(l.equals(r)));
+ case if_acmpne:
+ return syms.booleanType.constType(b2i(!l.equals(r)));
+ case string_add:
+ return syms.stringType.constType(
+ left.stringValue() + right.stringValue());
+ default:
+ return null;
+ }
+ }
+ } catch (ArithmeticException e) {
+ return null;
+ }
+ }
+
+ /** Coerce constant type to target type.
+ * @param etype The source type of the coercion,
+ * which is assumed to be a constant type compatible with
+ * ttype.
+ * @param ttype The target type of the coercion.
+ */
+ Type coerce(Type etype, Type ttype) {
+ // WAS if (etype.baseType() == ttype.baseType())
+ if (etype.tsym.type == ttype.tsym.type)
+ return etype;
+ if (etype.isNumeric()) {
+ Object n = etype.constValue();
+ switch (ttype.getTag()) {
+ case BYTE:
+ return syms.byteType.constType(0 + (byte)intValue(n));
+ case CHAR:
+ return syms.charType.constType(0 + (char)intValue(n));
+ case SHORT:
+ return syms.shortType.constType(0 + (short)intValue(n));
+ case INT:
+ return syms.intType.constType(intValue(n));
+ case LONG:
+ return syms.longType.constType(longValue(n));
+ case FLOAT:
+ return syms.floatType.constType(floatValue(n));
+ case DOUBLE:
+ return syms.doubleType.constType(doubleValue(n));
+ }
+ }
+ return ttype;
+ }
+}