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

Mon, 10 Dec 2012 16:21:26 +0000

author
vromero
date
Mon, 10 Dec 2012 16:21:26 +0000
changeset 1442
fcf89720ae71
parent 1374
c002fdee76fd
child 1521
71f35e4b93a5
permissions
-rw-r--r--

8003967: detect and remove all mutable implicit static enum fields in langtools
Reviewed-by: jjg

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

mercurial