duke@1: /*
duke@1: * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1: *
duke@1: * This code is free software; you can redistribute it and/or modify it
duke@1: * under the terms of the GNU General Public License version 2 only, as
duke@1: * published by the Free Software Foundation. Sun designates this
duke@1: * particular file as subject to the "Classpath" exception as provided
duke@1: * by Sun in the LICENSE file that accompanied this code.
duke@1: *
duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1: * version 2 for more details (a copy is included in the LICENSE file that
duke@1: * accompanied this code).
duke@1: *
duke@1: * You should have received a copy of the GNU General Public License version
duke@1: * 2 along with this work; if not, write to the Free Software Foundation,
duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1: *
duke@1: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1: * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1: * have any questions.
duke@1: */
duke@1:
duke@1: package com.sun.tools.javac.comp;
duke@1:
duke@1: import com.sun.tools.javac.code.*;
duke@1: import com.sun.tools.javac.jvm.*;
duke@1: import com.sun.tools.javac.util.*;
duke@1:
duke@1: import com.sun.tools.javac.code.Type.*;
duke@1:
duke@1: import static com.sun.tools.javac.code.TypeTags.*;
duke@1: import static com.sun.tools.javac.jvm.ByteCodes.*;
duke@1:
duke@1: /** Helper class for constant folding, used by the attribution phase.
duke@1: * This class is marked strictfp as mandated by JLS 15.4.
duke@1: *
duke@1: *
This is NOT part of any API supported by Sun Microsystems. If
duke@1: * you write code that depends on this, you do so at your own risk.
duke@1: * This code and its internal interfaces are subject to change or
duke@1: * deletion without notice.
duke@1: */
duke@1: strictfp class ConstFold {
duke@1: protected static final Context.Key constFoldKey =
duke@1: new Context.Key();
duke@1:
duke@1: private Symtab syms;
duke@1:
duke@1: public static ConstFold instance(Context context) {
duke@1: ConstFold instance = context.get(constFoldKey);
duke@1: if (instance == null)
duke@1: instance = new ConstFold(context);
duke@1: return instance;
duke@1: }
duke@1:
duke@1: private ConstFold(Context context) {
duke@1: context.put(constFoldKey, this);
duke@1:
duke@1: syms = Symtab.instance(context);
duke@1: }
duke@1:
duke@1: static Integer minusOne = -1;
duke@1: static Integer zero = 0;
duke@1: static Integer one = 1;
duke@1:
duke@1: /** Convert boolean to integer (true = 1, false = 0).
duke@1: */
duke@1: private static Integer b2i(boolean b) {
duke@1: return b ? one : zero;
duke@1: }
duke@1: private static int intValue(Object x) { return ((Number)x).intValue(); }
duke@1: private static long longValue(Object x) { return ((Number)x).longValue(); }
duke@1: private static float floatValue(Object x) { return ((Number)x).floatValue(); }
duke@1: private static double doubleValue(Object x) { return ((Number)x).doubleValue(); }
duke@1:
duke@1: /** Fold binary or unary operation, returning constant type reflecting the
duke@1: * operations result. Return null if fold failed due to an
duke@1: * arithmetic exception.
duke@1: * @param opcode The operation's opcode instruction (usually a byte code),
duke@1: * as entered by class Symtab.
duke@1: * @param argtypes The operation's argument types (a list of length 1 or 2).
duke@1: * Argument types are assumed to have non-null constValue's.
duke@1: */
duke@1: Type fold(int opcode, List argtypes) {
duke@1: int argCount = argtypes.length();
duke@1: if (argCount == 1)
duke@1: return fold1(opcode, argtypes.head);
duke@1: else if (argCount == 2)
duke@1: return fold2(opcode, argtypes.head, argtypes.tail.head);
duke@1: else
duke@1: throw new AssertionError();
duke@1: }
duke@1:
duke@1: /** Fold unary operation.
duke@1: * @param opcode The operation's opcode instruction (usually a byte code),
duke@1: * as entered by class Symtab.
duke@1: * opcode's ifeq to ifge are for postprocessing
duke@1: * xcmp; ifxx pairs of instructions.
duke@1: * @param operand The operation's operand type.
duke@1: * Argument types are assumed to have non-null constValue's.
duke@1: */
duke@1: Type fold1(int opcode, Type operand) {
duke@1: try {
duke@1: Object od = operand.constValue();
duke@1: switch (opcode) {
duke@1: case nop:
duke@1: return operand;
duke@1: case ineg: // unary -
duke@1: return syms.intType.constType(-intValue(od));
duke@1: case ixor: // ~
duke@1: return syms.intType.constType(~intValue(od));
duke@1: case bool_not: // !
duke@1: return syms.booleanType.constType(b2i(intValue(od) == 0));
duke@1: case ifeq:
duke@1: return syms.booleanType.constType(b2i(intValue(od) == 0));
duke@1: case ifne:
duke@1: return syms.booleanType.constType(b2i(intValue(od) != 0));
duke@1: case iflt:
duke@1: return syms.booleanType.constType(b2i(intValue(od) < 0));
duke@1: case ifgt:
duke@1: return syms.booleanType.constType(b2i(intValue(od) > 0));
duke@1: case ifle:
duke@1: return syms.booleanType.constType(b2i(intValue(od) <= 0));
duke@1: case ifge:
duke@1: return syms.booleanType.constType(b2i(intValue(od) >= 0));
duke@1:
duke@1: case lneg: // unary -
duke@1: return syms.longType.constType(new Long(-longValue(od)));
duke@1: case lxor: // ~
duke@1: return syms.longType.constType(new Long(~longValue(od)));
duke@1:
duke@1: case fneg: // unary -
duke@1: return syms.floatType.constType(new Float(-floatValue(od)));
duke@1:
duke@1: case dneg: // ~
duke@1: return syms.doubleType.constType(new Double(-doubleValue(od)));
duke@1:
duke@1: default:
duke@1: return null;
duke@1: }
duke@1: } catch (ArithmeticException e) {
duke@1: return null;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Fold binary operation.
duke@1: * @param opcode The operation's opcode instruction (usually a byte code),
duke@1: * as entered by class Symtab.
duke@1: * opcode's ifeq to ifge are for postprocessing
duke@1: * xcmp; ifxx pairs of instructions.
duke@1: * @param left The type of the operation's left operand.
duke@1: * @param right The type of the operation's right operand.
duke@1: */
duke@1: Type fold2(int opcode, Type left, Type right) {
duke@1: try {
duke@1: if (opcode > ByteCodes.preMask) {
duke@1: // we are seeing a composite instruction of the form xcmp; ifxx.
duke@1: // In this case fold both instructions separately.
duke@1: Type t1 = fold2(opcode >> ByteCodes.preShift, left, right);
duke@1: return (t1.constValue() == null) ? t1
duke@1: : fold1(opcode & ByteCodes.preMask, t1);
duke@1: } else {
duke@1: Object l = left.constValue();
duke@1: Object r = right.constValue();
duke@1: switch (opcode) {
duke@1: case iadd:
duke@1: return syms.intType.constType(intValue(l) + intValue(r));
duke@1: case isub:
duke@1: return syms.intType.constType(intValue(l) - intValue(r));
duke@1: case imul:
duke@1: return syms.intType.constType(intValue(l) * intValue(r));
duke@1: case idiv:
duke@1: return syms.intType.constType(intValue(l) / intValue(r));
duke@1: case imod:
duke@1: return syms.intType.constType(intValue(l) % intValue(r));
duke@1: case iand:
duke@1: return (left.tag == BOOLEAN
duke@1: ? syms.booleanType : syms.intType)
duke@1: .constType(intValue(l) & intValue(r));
duke@1: case bool_and:
duke@1: return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0));
duke@1: case ior:
duke@1: return (left.tag == BOOLEAN
duke@1: ? syms.booleanType : syms.intType)
duke@1: .constType(intValue(l) | intValue(r));
duke@1: case bool_or:
duke@1: return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0));
duke@1: case ixor:
duke@1: return (left.tag == BOOLEAN
duke@1: ? syms.booleanType : syms.intType)
duke@1: .constType(intValue(l) ^ intValue(r));
duke@1: case ishl: case ishll:
duke@1: return syms.intType.constType(intValue(l) << intValue(r));
duke@1: case ishr: case ishrl:
duke@1: return syms.intType.constType(intValue(l) >> intValue(r));
duke@1: case iushr: case iushrl:
duke@1: return syms.intType.constType(intValue(l) >>> intValue(r));
duke@1: case if_icmpeq:
duke@1: return syms.booleanType.constType(
duke@1: b2i(intValue(l) == intValue(r)));
duke@1: case if_icmpne:
duke@1: return syms.booleanType.constType(
duke@1: b2i(intValue(l) != intValue(r)));
duke@1: case if_icmplt:
duke@1: return syms.booleanType.constType(
duke@1: b2i(intValue(l) < intValue(r)));
duke@1: case if_icmpgt:
duke@1: return syms.booleanType.constType(
duke@1: b2i(intValue(l) > intValue(r)));
duke@1: case if_icmple:
duke@1: return syms.booleanType.constType(
duke@1: b2i(intValue(l) <= intValue(r)));
duke@1: case if_icmpge:
duke@1: return syms.booleanType.constType(
duke@1: b2i(intValue(l) >= intValue(r)));
duke@1:
duke@1: case ladd:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) + longValue(r)));
duke@1: case lsub:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) - longValue(r)));
duke@1: case lmul:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) * longValue(r)));
duke@1: case ldiv:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) / longValue(r)));
duke@1: case lmod:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) % longValue(r)));
duke@1: case land:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) & longValue(r)));
duke@1: case lor:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) | longValue(r)));
duke@1: case lxor:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) ^ longValue(r)));
duke@1: case lshl: case lshll:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) << intValue(r)));
duke@1: case lshr: case lshrl:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) >> intValue(r)));
duke@1: case lushr:
duke@1: return syms.longType.constType(
duke@1: new Long(longValue(l) >>> intValue(r)));
duke@1: case lcmp:
duke@1: if (longValue(l) < longValue(r))
duke@1: return syms.intType.constType(minusOne);
duke@1: else if (longValue(l) > longValue(r))
duke@1: return syms.intType.constType(one);
duke@1: else
duke@1: return syms.intType.constType(zero);
duke@1: case fadd:
duke@1: return syms.floatType.constType(
duke@1: new Float(floatValue(l) + floatValue(r)));
duke@1: case fsub:
duke@1: return syms.floatType.constType(
duke@1: new Float(floatValue(l) - floatValue(r)));
duke@1: case fmul:
duke@1: return syms.floatType.constType(
duke@1: new Float(floatValue(l) * floatValue(r)));
duke@1: case fdiv:
duke@1: return syms.floatType.constType(
duke@1: new Float(floatValue(l) / floatValue(r)));
duke@1: case fmod:
duke@1: return syms.floatType.constType(
duke@1: new Float(floatValue(l) % floatValue(r)));
duke@1: case fcmpg: case fcmpl:
duke@1: if (floatValue(l) < floatValue(r))
duke@1: return syms.intType.constType(minusOne);
duke@1: else if (floatValue(l) > floatValue(r))
duke@1: return syms.intType.constType(one);
duke@1: else if (floatValue(l) == floatValue(r))
duke@1: return syms.intType.constType(zero);
duke@1: else if (opcode == fcmpg)
duke@1: return syms.intType.constType(one);
duke@1: else
duke@1: return syms.intType.constType(minusOne);
duke@1: case dadd:
duke@1: return syms.doubleType.constType(
duke@1: new Double(doubleValue(l) + doubleValue(r)));
duke@1: case dsub:
duke@1: return syms.doubleType.constType(
duke@1: new Double(doubleValue(l) - doubleValue(r)));
duke@1: case dmul:
duke@1: return syms.doubleType.constType(
duke@1: new Double(doubleValue(l) * doubleValue(r)));
duke@1: case ddiv:
duke@1: return syms.doubleType.constType(
duke@1: new Double(doubleValue(l) / doubleValue(r)));
duke@1: case dmod:
duke@1: return syms.doubleType.constType(
duke@1: new Double(doubleValue(l) % doubleValue(r)));
duke@1: case dcmpg: case dcmpl:
duke@1: if (doubleValue(l) < doubleValue(r))
duke@1: return syms.intType.constType(minusOne);
duke@1: else if (doubleValue(l) > doubleValue(r))
duke@1: return syms.intType.constType(one);
duke@1: else if (doubleValue(l) == doubleValue(r))
duke@1: return syms.intType.constType(zero);
duke@1: else if (opcode == dcmpg)
duke@1: return syms.intType.constType(one);
duke@1: else
duke@1: return syms.intType.constType(minusOne);
duke@1: case if_acmpeq:
duke@1: return syms.booleanType.constType(b2i(l.equals(r)));
duke@1: case if_acmpne:
duke@1: return syms.booleanType.constType(b2i(!l.equals(r)));
duke@1: case string_add:
duke@1: return syms.stringType.constType(
duke@1: left.stringValue() + right.stringValue());
duke@1: default:
duke@1: return null;
duke@1: }
duke@1: }
duke@1: } catch (ArithmeticException e) {
duke@1: return null;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Coerce constant type to target type.
duke@1: * @param etype The source type of the coercion,
duke@1: * which is assumed to be a constant type compatble with
duke@1: * ttype.
duke@1: * @param ttype The target type of the coercion.
duke@1: */
duke@1: Type coerce(Type etype, Type ttype) {
duke@1: // WAS if (etype.baseType() == ttype.baseType())
duke@1: if (etype.tsym.type == ttype.tsym.type)
duke@1: return etype;
duke@1: if (etype.tag <= DOUBLE) {
duke@1: Object n = etype.constValue();
duke@1: switch (ttype.tag) {
duke@1: case BYTE:
duke@1: return syms.byteType.constType(0 + (byte)intValue(n));
duke@1: case CHAR:
duke@1: return syms.charType.constType(0 + (char)intValue(n));
duke@1: case SHORT:
duke@1: return syms.shortType.constType(0 + (short)intValue(n));
duke@1: case INT:
duke@1: return syms.intType.constType(intValue(n));
duke@1: case LONG:
duke@1: return syms.longType.constType(longValue(n));
duke@1: case FLOAT:
duke@1: return syms.floatType.constType(floatValue(n));
duke@1: case DOUBLE:
duke@1: return syms.doubleType.constType(doubleValue(n));
duke@1: }
duke@1: }
duke@1: return ttype;
duke@1: }
duke@1: }