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 */ 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 static com.sun.tools.javac.code.TypeTag.BOOLEAN; 33 34 import static com.sun.tools.javac.jvm.ByteCodes.*; 35 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>(); 47 48 private Symtab syms; 49 instance(Context context)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 } 56 ConstFold(Context context)57 private ConstFold(Context context) { 58 context.put(constFoldKey, this); 59 60 syms = Symtab.instance(context); 61 } 62 63 static final Integer minusOne = -1; 64 static final Integer zero = 0; 65 static final Integer one = 1; 66 67 /** Convert boolean to integer (true = 1, false = 0). 68 */ b2i(boolean b)69 private static Integer b2i(boolean b) { 70 return b ? one : zero; 71 } intValue(Object x)72 private static int intValue(Object x) { return ((Number)x).intValue(); } longValue(Object x)73 private static long longValue(Object x) { return ((Number)x).longValue(); } floatValue(Object x)74 private static float floatValue(Object x) { return ((Number)x).floatValue(); } doubleValue(Object x)75 private static double doubleValue(Object x) { return ((Number)x).doubleValue(); } 76 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 */ fold(int opcode, List<Type> argtypes)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 } 94 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 */ fold1(int opcode, Type operand)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)); 127 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))); 132 133 case fneg: // unary - 134 return syms.floatType.constType(new Float(-floatValue(od))); 135 136 case dneg: // ~ 137 return syms.doubleType.constType(new Double(-doubleValue(od))); 138 139 default: 140 return null; 141 } 142 } catch (ArithmeticException e) { 143 return null; 144 } 145 } 146 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 */ fold2(int opcode, Type left, Type right)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))); 217 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 } 325 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 */ coerce(Type etype, Type ttype)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 } 358