1/* 2 * Copyright (c) 1999, 2017, 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 unary operation. 77 * @param opcode The operation's opcode instruction (usually a byte code), 78 * as entered by class Symtab. 79 * opcode's ifeq to ifge are for postprocessing 80 * xcmp; ifxx pairs of instructions. 81 * @param operand The operation's operand type. 82 * Argument types are assumed to have non-null constValue's. 83 */ 84 Type fold1(int opcode, Type operand) { 85 try { 86 Object od = operand.constValue(); 87 switch (opcode) { 88 case nop: 89 return operand; 90 case ineg: // unary - 91 return syms.intType.constType(-intValue(od)); 92 case ixor: // ~ 93 return syms.intType.constType(~intValue(od)); 94 case bool_not: // ! 95 return syms.booleanType.constType(b2i(intValue(od) == 0)); 96 case ifeq: 97 return syms.booleanType.constType(b2i(intValue(od) == 0)); 98 case ifne: 99 return syms.booleanType.constType(b2i(intValue(od) != 0)); 100 case iflt: 101 return syms.booleanType.constType(b2i(intValue(od) < 0)); 102 case ifgt: 103 return syms.booleanType.constType(b2i(intValue(od) > 0)); 104 case ifle: 105 return syms.booleanType.constType(b2i(intValue(od) <= 0)); 106 case ifge: 107 return syms.booleanType.constType(b2i(intValue(od) >= 0)); 108 109 case lneg: // unary - 110 return syms.longType.constType(Long.valueOf(-longValue(od))); 111 case lxor: // ~ 112 return syms.longType.constType(Long.valueOf(~longValue(od))); 113 114 case fneg: // unary - 115 return syms.floatType.constType(Float.valueOf(-floatValue(od))); 116 117 case dneg: // ~ 118 return syms.doubleType.constType(Double.valueOf(-doubleValue(od))); 119 120 default: 121 return null; 122 } 123 } catch (ArithmeticException e) { 124 return null; 125 } 126 } 127 128 /** Fold binary operation. 129 * @param opcode The operation's opcode instruction (usually a byte code), 130 * as entered by class Symtab. 131 * opcode's ifeq to ifge are for postprocessing 132 * xcmp; ifxx pairs of instructions. 133 * @param left The type of the operation's left operand. 134 * @param right The type of the operation's right operand. 135 */ 136 Type fold2(int opcode, Type left, Type right) { 137 try { 138 if (opcode > ByteCodes.preMask) { 139 // we are seeing a composite instruction of the form xcmp; ifxx. 140 // In this case fold both instructions separately. 141 Type t1 = fold2(opcode >> ByteCodes.preShift, left, right); 142 return (t1.constValue() == null) ? t1 143 : fold1(opcode & ByteCodes.preMask, t1); 144 } else { 145 Object l = left.constValue(); 146 Object r = right.constValue(); 147 switch (opcode) { 148 case iadd: 149 return syms.intType.constType(intValue(l) + intValue(r)); 150 case isub: 151 return syms.intType.constType(intValue(l) - intValue(r)); 152 case imul: 153 return syms.intType.constType(intValue(l) * intValue(r)); 154 case idiv: 155 return syms.intType.constType(intValue(l) / intValue(r)); 156 case imod: 157 return syms.intType.constType(intValue(l) % intValue(r)); 158 case iand: 159 return (left.hasTag(BOOLEAN) 160 ? syms.booleanType : syms.intType) 161 .constType(intValue(l) & intValue(r)); 162 case bool_and: 163 return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0)); 164 case ior: 165 return (left.hasTag(BOOLEAN) 166 ? syms.booleanType : syms.intType) 167 .constType(intValue(l) | intValue(r)); 168 case bool_or: 169 return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0)); 170 case ixor: 171 return (left.hasTag(BOOLEAN) 172 ? syms.booleanType : syms.intType) 173 .constType(intValue(l) ^ intValue(r)); 174 case ishl: case ishll: 175 return syms.intType.constType(intValue(l) << intValue(r)); 176 case ishr: case ishrl: 177 return syms.intType.constType(intValue(l) >> intValue(r)); 178 case iushr: case iushrl: 179 return syms.intType.constType(intValue(l) >>> intValue(r)); 180 case if_icmpeq: 181 return syms.booleanType.constType( 182 b2i(intValue(l) == intValue(r))); 183 case if_icmpne: 184 return syms.booleanType.constType( 185 b2i(intValue(l) != intValue(r))); 186 case if_icmplt: 187 return syms.booleanType.constType( 188 b2i(intValue(l) < intValue(r))); 189 case if_icmpgt: 190 return syms.booleanType.constType( 191 b2i(intValue(l) > intValue(r))); 192 case if_icmple: 193 return syms.booleanType.constType( 194 b2i(intValue(l) <= intValue(r))); 195 case if_icmpge: 196 return syms.booleanType.constType( 197 b2i(intValue(l) >= intValue(r))); 198 199 case ladd: 200 return syms.longType.constType( 201 Long.valueOf(longValue(l) + longValue(r))); 202 case lsub: 203 return syms.longType.constType( 204 Long.valueOf(longValue(l) - longValue(r))); 205 case lmul: 206 return syms.longType.constType( 207 Long.valueOf(longValue(l) * longValue(r))); 208 case ldiv: 209 return syms.longType.constType( 210 Long.valueOf(longValue(l) / longValue(r))); 211 case lmod: 212 return syms.longType.constType( 213 Long.valueOf(longValue(l) % longValue(r))); 214 case land: 215 return syms.longType.constType( 216 Long.valueOf(longValue(l) & longValue(r))); 217 case lor: 218 return syms.longType.constType( 219 Long.valueOf(longValue(l) | longValue(r))); 220 case lxor: 221 return syms.longType.constType( 222 Long.valueOf(longValue(l) ^ longValue(r))); 223 case lshl: case lshll: 224 return syms.longType.constType( 225 Long.valueOf(longValue(l) << intValue(r))); 226 case lshr: case lshrl: 227 return syms.longType.constType( 228 Long.valueOf(longValue(l) >> intValue(r))); 229 case lushr: 230 return syms.longType.constType( 231 Long.valueOf(longValue(l) >>> intValue(r))); 232 case lcmp: 233 if (longValue(l) < longValue(r)) 234 return syms.intType.constType(minusOne); 235 else if (longValue(l) > longValue(r)) 236 return syms.intType.constType(one); 237 else 238 return syms.intType.constType(zero); 239 case fadd: 240 return syms.floatType.constType( 241 Float.valueOf(floatValue(l) + floatValue(r))); 242 case fsub: 243 return syms.floatType.constType( 244 Float.valueOf(floatValue(l) - floatValue(r))); 245 case fmul: 246 return syms.floatType.constType( 247 Float.valueOf(floatValue(l) * floatValue(r))); 248 case fdiv: 249 return syms.floatType.constType( 250 Float.valueOf(floatValue(l) / floatValue(r))); 251 case fmod: 252 return syms.floatType.constType( 253 Float.valueOf(floatValue(l) % floatValue(r))); 254 case fcmpg: case fcmpl: 255 if (floatValue(l) < floatValue(r)) 256 return syms.intType.constType(minusOne); 257 else if (floatValue(l) > floatValue(r)) 258 return syms.intType.constType(one); 259 else if (floatValue(l) == floatValue(r)) 260 return syms.intType.constType(zero); 261 else if (opcode == fcmpg) 262 return syms.intType.constType(one); 263 else 264 return syms.intType.constType(minusOne); 265 case dadd: 266 return syms.doubleType.constType( 267 Double.valueOf(doubleValue(l) + doubleValue(r))); 268 case dsub: 269 return syms.doubleType.constType( 270 Double.valueOf(doubleValue(l) - doubleValue(r))); 271 case dmul: 272 return syms.doubleType.constType( 273 Double.valueOf(doubleValue(l) * doubleValue(r))); 274 case ddiv: 275 return syms.doubleType.constType( 276 Double.valueOf(doubleValue(l) / doubleValue(r))); 277 case dmod: 278 return syms.doubleType.constType( 279 Double.valueOf(doubleValue(l) % doubleValue(r))); 280 case dcmpg: case dcmpl: 281 if (doubleValue(l) < doubleValue(r)) 282 return syms.intType.constType(minusOne); 283 else if (doubleValue(l) > doubleValue(r)) 284 return syms.intType.constType(one); 285 else if (doubleValue(l) == doubleValue(r)) 286 return syms.intType.constType(zero); 287 else if (opcode == dcmpg) 288 return syms.intType.constType(one); 289 else 290 return syms.intType.constType(minusOne); 291 case if_acmpeq: 292 return syms.booleanType.constType(b2i(l.equals(r))); 293 case if_acmpne: 294 return syms.booleanType.constType(b2i(!l.equals(r))); 295 case string_add: 296 return syms.stringType.constType( 297 left.stringValue() + right.stringValue()); 298 default: 299 return null; 300 } 301 } 302 } catch (ArithmeticException e) { 303 return null; 304 } 305 } 306 307 /** Coerce constant type to target type. 308 * @param etype The source type of the coercion, 309 * which is assumed to be a constant type compatible with 310 * ttype. 311 * @param ttype The target type of the coercion. 312 */ 313 Type coerce(Type etype, Type ttype) { 314 // WAS if (etype.baseType() == ttype.baseType()) 315 if (etype.tsym.type == ttype.tsym.type) 316 return etype; 317 if (etype.isNumeric()) { 318 Object n = etype.constValue(); 319 switch (ttype.getTag()) { 320 case BYTE: 321 return syms.byteType.constType(0 + (byte)intValue(n)); 322 case CHAR: 323 return syms.charType.constType(0 + (char)intValue(n)); 324 case SHORT: 325 return syms.shortType.constType(0 + (short)intValue(n)); 326 case INT: 327 return syms.intType.constType(intValue(n)); 328 case LONG: 329 return syms.longType.constType(longValue(n)); 330 case FLOAT: 331 return syms.floatType.constType(floatValue(n)); 332 case DOUBLE: 333 return syms.doubleType.constType(doubleValue(n)); 334 } 335 } 336 return ttype; 337 } 338} 339