1 /*
   2  * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import com.sun.tools.javac.code.*;
  29 import com.sun.tools.javac.code.Symbol.OperatorSymbol;
  30 import com.sun.tools.javac.jvm.*;
  31 import com.sun.tools.javac.util.*;
  32 
  33 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  34 
  35 import static com.sun.tools.javac.code.TypeTag.BOT;
  36 import static com.sun.tools.javac.code.TypeTag.CHAR;
  37 import static com.sun.tools.javac.jvm.ByteCodes.*;
  38 
  39 /** Helper class for constant folding, used by the attribution phase.
  40  *  This class is marked strictfp as mandated by JLS 15.4.
  41  *
  42  *  <p><b>This is NOT part of any supported API.
  43  *  If you write code that depends on this, you do so at your own risk.
  44  *  This code and its internal interfaces are subject to change or
  45  *  deletion without notice.</b>
  46  */
  47 strictfp public class ConstFold {
  48     protected static final Context.Key<ConstFold> constFoldKey = new Context.Key<>();
  49 
  50     private Symtab syms;
  51     private Types types;
  52 
  53     public static ConstFold instance(Context context) {
  54         ConstFold instance = context.get(constFoldKey);
  55         if (instance == null)
  56             instance = new ConstFold(context);
  57         return instance;
  58     }
  59 
  60     private ConstFold(Context context) {
  61         context.put(constFoldKey, this);
  62 
  63         syms = Symtab.instance(context);
  64         types = Types.instance(context);
  65     }
  66 
  67     static final Integer minusOne = -1;
  68     static final Integer zero     = 0;
  69     static final Integer one      = 1;
  70 
  71    /** Convert boolean to integer (true = 1, false = 0).
  72     */
  73     private static Integer b2i(boolean b) {
  74         return b ? one : zero;
  75     }
  76     private static int intValue(Object x) { return ((Number)x).intValue(); }
  77     private static long longValue(Object x) { return ((Number)x).longValue(); }
  78     private static float floatValue(Object x) { return ((Number)x).floatValue(); }
  79     private static double doubleValue(Object x) { return ((Number)x).doubleValue(); }
  80     public static String stringValue(TypeTag tag, Object x) {
  81         if (tag == BOT) {
  82             return "null";
  83         } else if (tag == BOOLEAN) {
  84             return ((Integer)x).intValue() == 0 ? "false" : "true";
  85         } else if (tag == CHAR) {
  86             return String.valueOf((char) ((Integer)x).intValue());
  87         } else {
  88             return x.toString();
  89         }
  90     }
  91     public static boolean isTrue(TypeTag tag, Object x) {
  92         return tag == BOOLEAN &&
  93                 x != null &&
  94                 ((Integer)x).intValue() != 0;
  95     }
  96     public static boolean isFalse(TypeTag tag, Object x) {
  97         return tag == BOOLEAN &&
  98                 x != null &&
  99                 ((Integer)x).intValue() == 0;
 100     }
 101 
 102     Type fold1(OperatorSymbol op, Type od) {
 103         if (op.opcode == nop) {
 104             return od;
 105         } else {
 106             Object v = fold1(op, od.constValue());
 107             Type foldType = foldType(op);
 108             return (foldType != null && v != null) ?
 109                     foldType(op).constType(v) :
 110                     null;
 111         }
 112     }
 113 
 114     /** Fold unary operation.
 115      *  @param op        The operator symbol.
 116      *                   opcode's ifeq to ifge are for postprocessing
 117      *                   xcmp; ifxx pairs of instructions.
 118      *  @param od        The operation's operand. Assumed to be non-null.
 119      */
 120     Object fold1(OperatorSymbol op, Object od) {
 121         int opcode = op.opcode;
 122         try {
 123             switch (opcode) {
 124                 case ineg: // unary -
 125                     return -intValue(od);
 126                 case ixor: // ~
 127                     return ~intValue(od);
 128                 case bool_not: // !
 129                     return b2i(intValue(od) == 0);
 130                 case ifeq:
 131                     return b2i(intValue(od) == 0);
 132                 case ifne:
 133                     return b2i(intValue(od) != 0);
 134                 case iflt:
 135                     return b2i(intValue(od) < 0);
 136                 case ifgt:
 137                     return b2i(intValue(od) > 0);
 138                 case ifle:
 139                     return b2i(intValue(od) <= 0);
 140                 case ifge:
 141                     return b2i(intValue(od) >= 0);
 142 
 143                 case lneg: // unary -
 144                     return Long.valueOf(-longValue(od));
 145                 case lxor: // ~
 146                     return Long.valueOf(~longValue(od));
 147 
 148                 case fneg: // unary -
 149                     return Float.valueOf(-floatValue(od));
 150 
 151                 case dneg: // ~
 152                     return Double.valueOf(-doubleValue(od));
 153 
 154                 default:
 155                     return null;
 156             }
 157         } catch (ArithmeticException e) {
 158             return null;
 159         }
 160     }
 161 
 162     Type fold2(OperatorSymbol op, Type left, Type right) {
 163         Object v = fold2(op, left.constValue(), right.constValue());
 164         Type foldType = foldType(op);
 165         return (foldType != null && v != null) ?
 166                 foldType(op).constType(v) :
 167                 null;
 168     }
 169 
 170     /** Fold binary operation.
 171      *  @param op        The operator symbol.
 172      *  @param l         The operation's left operand.
 173      *  @param r         The operation's right operand.
 174      */
 175     Object fold2(OperatorSymbol op, Object l, Object r) {
 176         int opcode = op.opcode;
 177         try {
 178             if (opcode > ByteCodes.preMask) {
 179                 // we are seeing a composite instruction of the form xcmp; ifxx.
 180                 // In this case fold both instructions separately.
 181                 Object t1 = fold2(op.pre(types), l, r);
 182                 return (t1 == null) ? t1
 183                     : fold1(op.post(types), t1);
 184             } else {
 185                 switch (opcode) {
 186                 case iadd:
 187                     return intValue(l) + intValue(r);
 188                 case isub:
 189                     return intValue(l) - intValue(r);
 190                 case imul:
 191                     return intValue(l) * intValue(r);
 192                 case idiv:
 193                     return intValue(l) / intValue(r);
 194                 case imod:
 195                     return intValue(l) % intValue(r);
 196                 case iand:
 197                     return intValue(l) & intValue(r);
 198                 case bool_and:
 199                     return b2i((intValue(l) & intValue(r)) != 0);
 200                 case ior:
 201                     return intValue(l) | intValue(r);
 202                 case bool_or:
 203                     return b2i((intValue(l) | intValue(r)) != 0);
 204                 case ixor:
 205                     return intValue(l) ^ intValue(r);
 206                 case ishl: case ishll:
 207                     return intValue(l) << intValue(r);
 208                 case ishr: case ishrl:
 209                     return intValue(l) >> intValue(r);
 210                 case iushr: case iushrl:
 211                     return intValue(l) >>> intValue(r);
 212                 case if_icmpeq:
 213                     return b2i(intValue(l) == intValue(r));
 214                 case if_icmpne:
 215                     return b2i(intValue(l) != intValue(r));
 216                 case if_icmplt:
 217                     return b2i(intValue(l) < intValue(r));
 218                 case if_icmpgt:
 219                     return b2i(intValue(l) > intValue(r));
 220                 case if_icmple:
 221                     return b2i(intValue(l) <= intValue(r));
 222                 case if_icmpge:
 223                     return b2i(intValue(l) >= intValue(r));
 224 
 225                 case ladd:
 226                     return Long.valueOf(longValue(l) + longValue(r));
 227                 case lsub:
 228                     return Long.valueOf(longValue(l) - longValue(r));
 229                 case lmul:
 230                     return Long.valueOf(longValue(l) * longValue(r));
 231                 case ldiv:
 232                     return Long.valueOf(longValue(l) / longValue(r));
 233                 case lmod:
 234                     return Long.valueOf(longValue(l) % longValue(r));
 235                 case land:
 236                     return Long.valueOf(longValue(l) & longValue(r));
 237                 case lor:
 238                     return Long.valueOf(longValue(l) | longValue(r));
 239                 case lxor:
 240                     return Long.valueOf(longValue(l) ^ longValue(r));
 241                 case lshl: case lshll:
 242                     return Long.valueOf(longValue(l) << intValue(r));
 243                 case lshr: case lshrl:
 244                     return Long.valueOf(longValue(l) >> intValue(r));
 245                 case lushr:
 246                     return Long.valueOf(longValue(l) >>> intValue(r));
 247                 case lcmp:
 248                     if (longValue(l) < longValue(r))
 249                         return minusOne;
 250                     else if (longValue(l) > longValue(r))
 251                         return one;
 252                     else
 253                         return zero;
 254                 case fadd:
 255                     return Float.valueOf(floatValue(l) + floatValue(r));
 256                 case fsub:
 257                     return Float.valueOf(floatValue(l) - floatValue(r));
 258                 case fmul:
 259                     return Float.valueOf(floatValue(l) * floatValue(r));
 260                 case fdiv:
 261                     return Float.valueOf(floatValue(l) / floatValue(r));
 262                 case fmod:
 263                     return Float.valueOf(floatValue(l) % floatValue(r));
 264                 case fcmpg: case fcmpl:
 265                     if (floatValue(l) < floatValue(r))
 266                         return minusOne;
 267                     else if (floatValue(l) > floatValue(r))
 268                         return one;
 269                     else if (floatValue(l) == floatValue(r))
 270                         return zero;
 271                     else if (opcode == fcmpg)
 272                         return one;
 273                     else
 274                         return minusOne;
 275                 case dadd:
 276                     return Double.valueOf(doubleValue(l) + doubleValue(r));
 277                 case dsub:
 278                     return Double.valueOf(doubleValue(l) - doubleValue(r));
 279                 case dmul:
 280                     return Double.valueOf(doubleValue(l) * doubleValue(r));
 281                 case ddiv:
 282                     return Double.valueOf(doubleValue(l) / doubleValue(r));
 283                 case dmod:
 284                     return syms.doubleType.constType(
 285                         Double.valueOf(doubleValue(l) % doubleValue(r)));
 286                 case dcmpg: case dcmpl:
 287                     if (doubleValue(l) < doubleValue(r))
 288                         return minusOne;
 289                     else if (doubleValue(l) > doubleValue(r))
 290                         return one;
 291                     else if (doubleValue(l) == doubleValue(r))
 292                         return zero;
 293                     else if (opcode == dcmpg)
 294                         return one;
 295                     else
 296                         return minusOne;
 297                 case if_acmpeq:
 298                     return b2i(l.equals(r));
 299                 case if_acmpne:
 300                     return b2i(!l.equals(r));
 301                 case string_add: {
 302                     List<Type> params = op.type.getParameterTypes();
 303                     return stringValue(params.head.getTag(), l) + stringValue(params.tail.head.getTag(), r);
 304                 }
 305                 default:
 306                     return null;
 307                 }
 308             }
 309         } catch (ArithmeticException e) {
 310             return null;
 311         }
 312     }
 313 
 314     /** Fold binary operation.
 315      *  @param opcode    The operation's opcode instruction (usually a byte code),
 316      *                   as entered by class Symtab.
 317      *                   opcode's ifeq to ifge are for postprocessing
 318      *                   xcmp; ifxx pairs of instructions.
 319      *  @param left      The type of the operation's left operand.
 320      *  @param right     The type of the operation's right operand.
 321      */
 322     Type foldType(OperatorSymbol op) {
 323         int opcode = op.opcode;
 324         if (opcode > ByteCodes.preMask) {
 325             // we are seeing a composite instruction of the form xcmp; ifxx.
 326             // In this case fold both instructions separately.
 327             return syms.booleanType;
 328         } else {
 329             switch (opcode) {
 330                 case iadd: case isub: case imul: case idiv: case imod:
 331                 case ishl: case ishll: case ishr: case ishrl: case iushr: case iushrl:
 332                 case ineg: case lcmp: case fcmpg: case fcmpl: case dcmpg: case dcmpl:
 333                     return syms.intType;
 334                 case bool_and: case bool_or: case if_icmpeq: case if_icmpne: case if_icmplt: case if_icmpgt:
 335                 case if_icmple: case if_icmpge: case if_acmpeq: case if_acmpne: case bool_not: case ifeq:
 336                 case ifne: case iflt: case ifgt: case ifle: case ifge:
 337                     return syms.booleanType;
 338                 case ior: case iand: case ixor:
 339                     return (op.type.getParameterTypes().head.hasTag(BOOLEAN)
 340                       ? syms.booleanType : syms.intType);
 341                 case ladd: case lsub: case lmul: case ldiv: case lmod: case land:
 342                 case lor: case lxor: case lshl: case lshll: case lshr: case lshrl: case lneg:
 343                 case lushr:
 344                     return syms.longType;
 345                 case fadd: case fsub: case fmul: case fdiv: case fmod: case fneg:
 346                     return syms.floatType;
 347                 case dadd: case dsub: case dmul: case ddiv: case dmod: case dneg:
 348                     return syms.doubleType;
 349                 case string_add:
 350                     return syms.stringType;
 351                 default:
 352                     return null;
 353             }
 354         }
 355     }
 356 
 357     /** Coerce constant type to target type.
 358      *  @param etype      The source type of the coercion,
 359      *                    which is assumed to be a constant type compatible with
 360      *                    ttype.
 361      *  @param ttype      The target type of the coercion.
 362      */
 363     Type coerce(Type etype, Type ttype) {
 364         // WAS if (etype.baseType() == ttype.baseType())
 365         if (etype.tsym.type == ttype.tsym.type)
 366             return etype;
 367         if (etype.isNumeric()) {
 368             Object n = etype.constValue();
 369             switch (ttype.getTag()) {
 370             case BYTE:
 371                 return syms.byteType.constType(0 + (byte)intValue(n));
 372             case CHAR:
 373                 return syms.charType.constType(0 + (char)intValue(n));
 374             case SHORT:
 375                 return syms.shortType.constType(0 + (short)intValue(n));
 376             case INT:
 377                 return syms.intType.constType(intValue(n));
 378             case LONG:
 379                 return syms.longType.constType(longValue(n));
 380             case FLOAT:
 381                 return syms.floatType.constType(floatValue(n));
 382             case DOUBLE:
 383                 return syms.doubleType.constType(doubleValue(n));
 384             }
 385         }
 386         return ttype;
 387     }
 388 }