langtools/src/share/classes/com/sun/tools/javac/comp/ConstFold.java
changeset 10 06bc494ca11e
child 5520 86e4b9a9da40
equal deleted inserted replaced
0:fd16c54261b3 10:06bc494ca11e
       
     1 /*
       
     2  * Copyright 1999-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.javac.comp;
       
    27 
       
    28 import com.sun.tools.javac.code.*;
       
    29 import com.sun.tools.javac.jvm.*;
       
    30 import com.sun.tools.javac.util.*;
       
    31 
       
    32 import com.sun.tools.javac.code.Type.*;
       
    33 
       
    34 import static com.sun.tools.javac.code.TypeTags.*;
       
    35 import static com.sun.tools.javac.jvm.ByteCodes.*;
       
    36 
       
    37 /** Helper class for constant folding, used by the attribution phase.
       
    38  *  This class is marked strictfp as mandated by JLS 15.4.
       
    39  *
       
    40  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
       
    41  *  you write code that depends on this, you do so at your own risk.
       
    42  *  This code and its internal interfaces are subject to change or
       
    43  *  deletion without notice.</b>
       
    44  */
       
    45 strictfp class ConstFold {
       
    46     protected static final Context.Key<ConstFold> constFoldKey =
       
    47         new Context.Key<ConstFold>();
       
    48 
       
    49     private Symtab syms;
       
    50 
       
    51     public static ConstFold instance(Context context) {
       
    52         ConstFold instance = context.get(constFoldKey);
       
    53         if (instance == null)
       
    54             instance = new ConstFold(context);
       
    55         return instance;
       
    56     }
       
    57 
       
    58     private ConstFold(Context context) {
       
    59         context.put(constFoldKey, this);
       
    60 
       
    61         syms = Symtab.instance(context);
       
    62     }
       
    63 
       
    64     static Integer minusOne = -1;
       
    65     static Integer zero     = 0;
       
    66     static Integer one      = 1;
       
    67 
       
    68    /** Convert boolean to integer (true = 1, false = 0).
       
    69     */
       
    70     private static Integer b2i(boolean b) {
       
    71         return b ? one : zero;
       
    72     }
       
    73     private static int intValue(Object x) { return ((Number)x).intValue(); }
       
    74     private static long longValue(Object x) { return ((Number)x).longValue(); }
       
    75     private static float floatValue(Object x) { return ((Number)x).floatValue(); }
       
    76     private static double doubleValue(Object x) { return ((Number)x).doubleValue(); }
       
    77 
       
    78     /** Fold binary or unary operation, returning constant type reflecting the
       
    79      *  operations result. Return null if fold failed due to an
       
    80      *  arithmetic exception.
       
    81      *  @param opcode    The operation's opcode instruction (usually a byte code),
       
    82      *                   as entered by class Symtab.
       
    83      *  @param argtypes  The operation's argument types (a list of length 1 or 2).
       
    84      *                   Argument types are assumed to have non-null constValue's.
       
    85      */
       
    86     Type fold(int opcode, List<Type> argtypes) {
       
    87         int argCount = argtypes.length();
       
    88         if (argCount == 1)
       
    89             return fold1(opcode, argtypes.head);
       
    90         else if (argCount == 2)
       
    91             return fold2(opcode, argtypes.head, argtypes.tail.head);
       
    92         else
       
    93             throw new AssertionError();
       
    94     }
       
    95 
       
    96     /** Fold unary operation.
       
    97      *  @param opcode    The operation's opcode instruction (usually a byte code),
       
    98      *                   as entered by class Symtab.
       
    99      *                   opcode's ifeq to ifge are for postprocessing
       
   100      *                   xcmp; ifxx pairs of instructions.
       
   101      *  @param operand   The operation's operand type.
       
   102      *                   Argument types are assumed to have non-null constValue's.
       
   103      */
       
   104     Type fold1(int opcode, Type operand) {
       
   105         try {
       
   106             Object od = operand.constValue();
       
   107             switch (opcode) {
       
   108             case nop:
       
   109                 return operand;
       
   110             case ineg: // unary -
       
   111                 return syms.intType.constType(-intValue(od));
       
   112             case ixor: // ~
       
   113                 return syms.intType.constType(~intValue(od));
       
   114             case bool_not: // !
       
   115                 return syms.booleanType.constType(b2i(intValue(od) == 0));
       
   116             case ifeq:
       
   117                 return syms.booleanType.constType(b2i(intValue(od) == 0));
       
   118             case ifne:
       
   119                 return syms.booleanType.constType(b2i(intValue(od) != 0));
       
   120             case iflt:
       
   121                 return syms.booleanType.constType(b2i(intValue(od) < 0));
       
   122             case ifgt:
       
   123                 return syms.booleanType.constType(b2i(intValue(od) > 0));
       
   124             case ifle:
       
   125                 return syms.booleanType.constType(b2i(intValue(od) <= 0));
       
   126             case ifge:
       
   127                 return syms.booleanType.constType(b2i(intValue(od) >= 0));
       
   128 
       
   129             case lneg: // unary -
       
   130                 return syms.longType.constType(new Long(-longValue(od)));
       
   131             case lxor: // ~
       
   132                 return syms.longType.constType(new Long(~longValue(od)));
       
   133 
       
   134             case fneg: // unary -
       
   135                 return syms.floatType.constType(new Float(-floatValue(od)));
       
   136 
       
   137             case dneg: // ~
       
   138                 return syms.doubleType.constType(new Double(-doubleValue(od)));
       
   139 
       
   140             default:
       
   141                 return null;
       
   142             }
       
   143         } catch (ArithmeticException e) {
       
   144             return null;
       
   145         }
       
   146     }
       
   147 
       
   148     /** Fold binary operation.
       
   149      *  @param opcode    The operation's opcode instruction (usually a byte code),
       
   150      *                   as entered by class Symtab.
       
   151      *                   opcode's ifeq to ifge are for postprocessing
       
   152      *                   xcmp; ifxx pairs of instructions.
       
   153      *  @param left      The type of the operation's left operand.
       
   154      *  @param right     The type of the operation's right operand.
       
   155      */
       
   156     Type fold2(int opcode, Type left, Type right) {
       
   157         try {
       
   158             if (opcode > ByteCodes.preMask) {
       
   159                 // we are seeing a composite instruction of the form xcmp; ifxx.
       
   160                 // In this case fold both instructions separately.
       
   161                 Type t1 = fold2(opcode >> ByteCodes.preShift, left, right);
       
   162                 return (t1.constValue() == null) ? t1
       
   163                     : fold1(opcode & ByteCodes.preMask, t1);
       
   164             } else {
       
   165                 Object l = left.constValue();
       
   166                 Object r = right.constValue();
       
   167                 switch (opcode) {
       
   168                 case iadd:
       
   169                     return syms.intType.constType(intValue(l) + intValue(r));
       
   170                 case isub:
       
   171                     return syms.intType.constType(intValue(l) - intValue(r));
       
   172                 case imul:
       
   173                     return syms.intType.constType(intValue(l) * intValue(r));
       
   174                 case idiv:
       
   175                     return syms.intType.constType(intValue(l) / intValue(r));
       
   176                 case imod:
       
   177                     return syms.intType.constType(intValue(l) % intValue(r));
       
   178                 case iand:
       
   179                     return (left.tag == BOOLEAN
       
   180                       ? syms.booleanType : syms.intType)
       
   181                       .constType(intValue(l) & intValue(r));
       
   182                 case bool_and:
       
   183                     return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0));
       
   184                 case ior:
       
   185                     return (left.tag == BOOLEAN
       
   186                       ? syms.booleanType : syms.intType)
       
   187                       .constType(intValue(l) | intValue(r));
       
   188                 case bool_or:
       
   189                     return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0));
       
   190                 case ixor:
       
   191                     return (left.tag == BOOLEAN
       
   192                       ? syms.booleanType : syms.intType)
       
   193                       .constType(intValue(l) ^ intValue(r));
       
   194                 case ishl: case ishll:
       
   195                     return syms.intType.constType(intValue(l) << intValue(r));
       
   196                 case ishr: case ishrl:
       
   197                     return syms.intType.constType(intValue(l) >> intValue(r));
       
   198                 case iushr: case iushrl:
       
   199                     return syms.intType.constType(intValue(l) >>> intValue(r));
       
   200                 case if_icmpeq:
       
   201                     return syms.booleanType.constType(
       
   202                         b2i(intValue(l) == intValue(r)));
       
   203                 case if_icmpne:
       
   204                     return syms.booleanType.constType(
       
   205                         b2i(intValue(l) != intValue(r)));
       
   206                 case if_icmplt:
       
   207                     return syms.booleanType.constType(
       
   208                         b2i(intValue(l) < intValue(r)));
       
   209                 case if_icmpgt:
       
   210                     return syms.booleanType.constType(
       
   211                         b2i(intValue(l) > intValue(r)));
       
   212                 case if_icmple:
       
   213                     return syms.booleanType.constType(
       
   214                         b2i(intValue(l) <= intValue(r)));
       
   215                 case if_icmpge:
       
   216                     return syms.booleanType.constType(
       
   217                         b2i(intValue(l) >= intValue(r)));
       
   218 
       
   219                 case ladd:
       
   220                     return syms.longType.constType(
       
   221                         new Long(longValue(l) + longValue(r)));
       
   222                 case lsub:
       
   223                     return syms.longType.constType(
       
   224                         new Long(longValue(l) - longValue(r)));
       
   225                 case lmul:
       
   226                     return syms.longType.constType(
       
   227                         new Long(longValue(l) * longValue(r)));
       
   228                 case ldiv:
       
   229                     return syms.longType.constType(
       
   230                         new Long(longValue(l) / longValue(r)));
       
   231                 case lmod:
       
   232                     return syms.longType.constType(
       
   233                         new Long(longValue(l) % longValue(r)));
       
   234                 case land:
       
   235                     return syms.longType.constType(
       
   236                         new Long(longValue(l) & longValue(r)));
       
   237                 case lor:
       
   238                     return syms.longType.constType(
       
   239                         new Long(longValue(l) | longValue(r)));
       
   240                 case lxor:
       
   241                     return syms.longType.constType(
       
   242                         new Long(longValue(l) ^ longValue(r)));
       
   243                 case lshl: case lshll:
       
   244                     return syms.longType.constType(
       
   245                         new Long(longValue(l) << intValue(r)));
       
   246                 case lshr: case lshrl:
       
   247                     return syms.longType.constType(
       
   248                         new Long(longValue(l) >> intValue(r)));
       
   249                 case lushr:
       
   250                     return syms.longType.constType(
       
   251                         new Long(longValue(l) >>> intValue(r)));
       
   252                 case lcmp:
       
   253                     if (longValue(l) < longValue(r))
       
   254                         return syms.intType.constType(minusOne);
       
   255                     else if (longValue(l) > longValue(r))
       
   256                         return syms.intType.constType(one);
       
   257                     else
       
   258                         return syms.intType.constType(zero);
       
   259                 case fadd:
       
   260                     return syms.floatType.constType(
       
   261                         new Float(floatValue(l) + floatValue(r)));
       
   262                 case fsub:
       
   263                     return syms.floatType.constType(
       
   264                         new Float(floatValue(l) - floatValue(r)));
       
   265                 case fmul:
       
   266                     return syms.floatType.constType(
       
   267                         new Float(floatValue(l) * floatValue(r)));
       
   268                 case fdiv:
       
   269                     return syms.floatType.constType(
       
   270                         new Float(floatValue(l) / floatValue(r)));
       
   271                 case fmod:
       
   272                     return syms.floatType.constType(
       
   273                         new Float(floatValue(l) % floatValue(r)));
       
   274                 case fcmpg: case fcmpl:
       
   275                     if (floatValue(l) < floatValue(r))
       
   276                         return syms.intType.constType(minusOne);
       
   277                     else if (floatValue(l) > floatValue(r))
       
   278                         return syms.intType.constType(one);
       
   279                     else if (floatValue(l) == floatValue(r))
       
   280                         return syms.intType.constType(zero);
       
   281                     else if (opcode == fcmpg)
       
   282                         return syms.intType.constType(one);
       
   283                     else
       
   284                         return syms.intType.constType(minusOne);
       
   285                 case dadd:
       
   286                     return syms.doubleType.constType(
       
   287                         new Double(doubleValue(l) + doubleValue(r)));
       
   288                 case dsub:
       
   289                     return syms.doubleType.constType(
       
   290                         new Double(doubleValue(l) - doubleValue(r)));
       
   291                 case dmul:
       
   292                     return syms.doubleType.constType(
       
   293                         new Double(doubleValue(l) * doubleValue(r)));
       
   294                 case ddiv:
       
   295                     return syms.doubleType.constType(
       
   296                         new Double(doubleValue(l) / doubleValue(r)));
       
   297                 case dmod:
       
   298                     return syms.doubleType.constType(
       
   299                         new Double(doubleValue(l) % doubleValue(r)));
       
   300                 case dcmpg: case dcmpl:
       
   301                     if (doubleValue(l) < doubleValue(r))
       
   302                         return syms.intType.constType(minusOne);
       
   303                     else if (doubleValue(l) > doubleValue(r))
       
   304                         return syms.intType.constType(one);
       
   305                     else if (doubleValue(l) == doubleValue(r))
       
   306                         return syms.intType.constType(zero);
       
   307                     else if (opcode == dcmpg)
       
   308                         return syms.intType.constType(one);
       
   309                     else
       
   310                         return syms.intType.constType(minusOne);
       
   311                 case if_acmpeq:
       
   312                     return syms.booleanType.constType(b2i(l.equals(r)));
       
   313                 case if_acmpne:
       
   314                     return syms.booleanType.constType(b2i(!l.equals(r)));
       
   315                 case string_add:
       
   316                     return syms.stringType.constType(
       
   317                         left.stringValue() + right.stringValue());
       
   318                 default:
       
   319                     return null;
       
   320                 }
       
   321             }
       
   322         } catch (ArithmeticException e) {
       
   323             return null;
       
   324         }
       
   325     }
       
   326 
       
   327     /** Coerce constant type to target type.
       
   328      *  @param etype      The source type of the coercion,
       
   329      *                    which is assumed to be a constant type compatble with
       
   330      *                    ttype.
       
   331      *  @param ttype      The target type of the coercion.
       
   332      */
       
   333      Type coerce(Type etype, Type ttype) {
       
   334          // WAS if (etype.baseType() == ttype.baseType())
       
   335          if (etype.tsym.type == ttype.tsym.type)
       
   336              return etype;
       
   337          if (etype.tag <= DOUBLE) {
       
   338              Object n = etype.constValue();
       
   339              switch (ttype.tag) {
       
   340              case BYTE:
       
   341                  return syms.byteType.constType(0 + (byte)intValue(n));
       
   342              case CHAR:
       
   343                  return syms.charType.constType(0 + (char)intValue(n));
       
   344              case SHORT:
       
   345                  return syms.shortType.constType(0 + (short)intValue(n));
       
   346              case INT:
       
   347                  return syms.intType.constType(intValue(n));
       
   348              case LONG:
       
   349                  return syms.longType.constType(longValue(n));
       
   350              case FLOAT:
       
   351                  return syms.floatType.constType(floatValue(n));
       
   352              case DOUBLE:
       
   353                  return syms.doubleType.constType(doubleValue(n));
       
   354              }
       
   355          }
       
   356          return ttype;
       
   357      }
       
   358 }