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