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