src/share/classes/com/sun/tools/javac/comp/ConstFold.java

Thu, 21 Feb 2013 15:19:29 +0000

author
mcimadamore
date
Thu, 21 Feb 2013 15:19:29 +0000
changeset 1595
d686d8a7eb78
parent 1521
71f35e4b93a5
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8008227: Mixing lambdas with anonymous classes leads to NPE thrown by compiler
Summary: Disentangle cyclic dependency between static-ness of synthetic lambda method and static-ness of classes nested within lambdas
Reviewed-by: jjg

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

mercurial