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 
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 = new Context.Key<>();
46 
47     private Symtab syms;
48 
instance(Context context)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 
ConstFold(Context context)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     */
b2i(boolean b)68     private static Integer b2i(boolean b) {
69         return b ? one : zero;
70     }
intValue(Object x)71     private static int intValue(Object x) { return ((Number)x).intValue(); }
longValue(Object x)72     private static long longValue(Object x) { return ((Number)x).longValue(); }
floatValue(Object x)73     private static float floatValue(Object x) { return ((Number)x).floatValue(); }
doubleValue(Object x)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      */
fold1(int opcode, Type operand)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      */
fold2(int opcode, Type left, Type right)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      */
coerce(Type etype, Type ttype)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