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