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