001    /*
002     * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.comp;
027    
028    import com.sun.tools.javac.code.*;
029    import com.sun.tools.javac.jvm.*;
030    import com.sun.tools.javac.util.*;
031    
032    import com.sun.tools.javac.code.Type.*;
033    
034    import static com.sun.tools.javac.code.TypeTags.*;
035    import static com.sun.tools.javac.jvm.ByteCodes.*;
036    
037    /** Helper class for constant folding, used by the attribution phase.
038     *  This class is marked strictfp as mandated by JLS 15.4.
039     *
040     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
041     *  you write code that depends on this, you do so at your own risk.
042     *  This code and its internal interfaces are subject to change or
043     *  deletion without notice.</b>
044     */
045    strictfp class ConstFold {
046        protected static final Context.Key<ConstFold> constFoldKey =
047            new Context.Key<ConstFold>();
048    
049        private Symtab syms;
050    
051        public static ConstFold instance(Context context) {
052            ConstFold instance = context.get(constFoldKey);
053            if (instance == null)
054                instance = new ConstFold(context);
055            return instance;
056        }
057    
058        private ConstFold(Context context) {
059            context.put(constFoldKey, this);
060    
061            syms = Symtab.instance(context);
062        }
063    
064        static Integer minusOne = -1;
065        static Integer zero     = 0;
066        static Integer one      = 1;
067    
068       /** Convert boolean to integer (true = 1, false = 0).
069        */
070        private static Integer b2i(boolean b) {
071            return b ? one : zero;
072        }
073        private static int intValue(Object x) { return ((Number)x).intValue(); }
074        private static long longValue(Object x) { return ((Number)x).longValue(); }
075        private static float floatValue(Object x) { return ((Number)x).floatValue(); }
076        private static double doubleValue(Object x) { return ((Number)x).doubleValue(); }
077    
078        /** Fold binary or unary operation, returning constant type reflecting the
079         *  operations result. Return null if fold failed due to an
080         *  arithmetic exception.
081         *  @param opcode    The operation's opcode instruction (usually a byte code),
082         *                   as entered by class Symtab.
083         *  @param argtypes  The operation's argument types (a list of length 1 or 2).
084         *                   Argument types are assumed to have non-null constValue's.
085         */
086        Type fold(int opcode, List<Type> argtypes) {
087            int argCount = argtypes.length();
088            if (argCount == 1)
089                return fold1(opcode, argtypes.head);
090            else if (argCount == 2)
091                return fold2(opcode, argtypes.head, argtypes.tail.head);
092            else
093                throw new AssertionError();
094        }
095    
096        /** Fold unary operation.
097         *  @param opcode    The operation's opcode instruction (usually a byte code),
098         *                   as entered by class Symtab.
099         *                   opcode's ifeq to ifge are for postprocessing
100         *                   xcmp; ifxx pairs of instructions.
101         *  @param operand   The operation's operand type.
102         *                   Argument types are assumed to have non-null constValue's.
103         */
104        Type fold1(int opcode, Type operand) {
105            try {
106                Object od = operand.constValue();
107                switch (opcode) {
108                case nop:
109                    return operand;
110                case ineg: // unary -
111                    return syms.intType.constType(-intValue(od));
112                case ixor: // ~
113                    return syms.intType.constType(~intValue(od));
114                case bool_not: // !
115                    return syms.booleanType.constType(b2i(intValue(od) == 0));
116                case ifeq:
117                    return syms.booleanType.constType(b2i(intValue(od) == 0));
118                case ifne:
119                    return syms.booleanType.constType(b2i(intValue(od) != 0));
120                case iflt:
121                    return syms.booleanType.constType(b2i(intValue(od) < 0));
122                case ifgt:
123                    return syms.booleanType.constType(b2i(intValue(od) > 0));
124                case ifle:
125                    return syms.booleanType.constType(b2i(intValue(od) <= 0));
126                case ifge:
127                    return syms.booleanType.constType(b2i(intValue(od) >= 0));
128    
129                case lneg: // unary -
130                    return syms.longType.constType(new Long(-longValue(od)));
131                case lxor: // ~
132                    return syms.longType.constType(new Long(~longValue(od)));
133    
134                case fneg: // unary -
135                    return syms.floatType.constType(new Float(-floatValue(od)));
136    
137                case dneg: // ~
138                    return syms.doubleType.constType(new Double(-doubleValue(od)));
139    
140                default:
141                    return null;
142                }
143            } catch (ArithmeticException e) {
144                return null;
145            }
146        }
147    
148        /** Fold binary operation.
149         *  @param opcode    The operation's opcode instruction (usually a byte code),
150         *                   as entered by class Symtab.
151         *                   opcode's ifeq to ifge are for postprocessing
152         *                   xcmp; ifxx pairs of instructions.
153         *  @param left      The type of the operation's left operand.
154         *  @param right     The type of the operation's right operand.
155         */
156        Type fold2(int opcode, Type left, Type right) {
157            try {
158                if (opcode > ByteCodes.preMask) {
159                    // we are seeing a composite instruction of the form xcmp; ifxx.
160                    // In this case fold both instructions separately.
161                    Type t1 = fold2(opcode >> ByteCodes.preShift, left, right);
162                    return (t1.constValue() == null) ? t1
163                        : fold1(opcode & ByteCodes.preMask, t1);
164                } else {
165                    Object l = left.constValue();
166                    Object r = right.constValue();
167                    switch (opcode) {
168                    case iadd:
169                        return syms.intType.constType(intValue(l) + intValue(r));
170                    case isub:
171                        return syms.intType.constType(intValue(l) - intValue(r));
172                    case imul:
173                        return syms.intType.constType(intValue(l) * intValue(r));
174                    case idiv:
175                        return syms.intType.constType(intValue(l) / intValue(r));
176                    case imod:
177                        return syms.intType.constType(intValue(l) % intValue(r));
178                    case iand:
179                        return (left.tag == BOOLEAN
180                          ? syms.booleanType : syms.intType)
181                          .constType(intValue(l) & intValue(r));
182                    case bool_and:
183                        return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0));
184                    case ior:
185                        return (left.tag == BOOLEAN
186                          ? syms.booleanType : syms.intType)
187                          .constType(intValue(l) | intValue(r));
188                    case bool_or:
189                        return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0));
190                    case ixor:
191                        return (left.tag == BOOLEAN
192                          ? syms.booleanType : syms.intType)
193                          .constType(intValue(l) ^ intValue(r));
194                    case ishl: case ishll:
195                        return syms.intType.constType(intValue(l) << intValue(r));
196                    case ishr: case ishrl:
197                        return syms.intType.constType(intValue(l) >> intValue(r));
198                    case iushr: case iushrl:
199                        return syms.intType.constType(intValue(l) >>> intValue(r));
200                    case if_icmpeq:
201                        return syms.booleanType.constType(
202                            b2i(intValue(l) == intValue(r)));
203                    case if_icmpne:
204                        return syms.booleanType.constType(
205                            b2i(intValue(l) != intValue(r)));
206                    case if_icmplt:
207                        return syms.booleanType.constType(
208                            b2i(intValue(l) < intValue(r)));
209                    case if_icmpgt:
210                        return syms.booleanType.constType(
211                            b2i(intValue(l) > intValue(r)));
212                    case if_icmple:
213                        return syms.booleanType.constType(
214                            b2i(intValue(l) <= intValue(r)));
215                    case if_icmpge:
216                        return syms.booleanType.constType(
217                            b2i(intValue(l) >= intValue(r)));
218    
219                    case ladd:
220                        return syms.longType.constType(
221                            new Long(longValue(l) + longValue(r)));
222                    case lsub:
223                        return syms.longType.constType(
224                            new Long(longValue(l) - longValue(r)));
225                    case lmul:
226                        return syms.longType.constType(
227                            new Long(longValue(l) * longValue(r)));
228                    case ldiv:
229                        return syms.longType.constType(
230                            new Long(longValue(l) / longValue(r)));
231                    case lmod:
232                        return syms.longType.constType(
233                            new Long(longValue(l) % longValue(r)));
234                    case land:
235                        return syms.longType.constType(
236                            new Long(longValue(l) & longValue(r)));
237                    case lor:
238                        return syms.longType.constType(
239                            new Long(longValue(l) | longValue(r)));
240                    case lxor:
241                        return syms.longType.constType(
242                            new Long(longValue(l) ^ longValue(r)));
243                    case lshl: case lshll:
244                        return syms.longType.constType(
245                            new Long(longValue(l) << intValue(r)));
246                    case lshr: case lshrl:
247                        return syms.longType.constType(
248                            new Long(longValue(l) >> intValue(r)));
249                    case lushr:
250                        return syms.longType.constType(
251                            new Long(longValue(l) >>> intValue(r)));
252                    case lcmp:
253                        if (longValue(l) < longValue(r))
254                            return syms.intType.constType(minusOne);
255                        else if (longValue(l) > longValue(r))
256                            return syms.intType.constType(one);
257                        else
258                            return syms.intType.constType(zero);
259                    case fadd:
260                        return syms.floatType.constType(
261                            new Float(floatValue(l) + floatValue(r)));
262                    case fsub:
263                        return syms.floatType.constType(
264                            new Float(floatValue(l) - floatValue(r)));
265                    case fmul:
266                        return syms.floatType.constType(
267                            new Float(floatValue(l) * floatValue(r)));
268                    case fdiv:
269                        return syms.floatType.constType(
270                            new Float(floatValue(l) / floatValue(r)));
271                    case fmod:
272                        return syms.floatType.constType(
273                            new Float(floatValue(l) % floatValue(r)));
274                    case fcmpg: case fcmpl:
275                        if (floatValue(l) < floatValue(r))
276                            return syms.intType.constType(minusOne);
277                        else if (floatValue(l) > floatValue(r))
278                            return syms.intType.constType(one);
279                        else if (floatValue(l) == floatValue(r))
280                            return syms.intType.constType(zero);
281                        else if (opcode == fcmpg)
282                            return syms.intType.constType(one);
283                        else
284                            return syms.intType.constType(minusOne);
285                    case dadd:
286                        return syms.doubleType.constType(
287                            new Double(doubleValue(l) + doubleValue(r)));
288                    case dsub:
289                        return syms.doubleType.constType(
290                            new Double(doubleValue(l) - doubleValue(r)));
291                    case dmul:
292                        return syms.doubleType.constType(
293                            new Double(doubleValue(l) * doubleValue(r)));
294                    case ddiv:
295                        return syms.doubleType.constType(
296                            new Double(doubleValue(l) / doubleValue(r)));
297                    case dmod:
298                        return syms.doubleType.constType(
299                            new Double(doubleValue(l) % doubleValue(r)));
300                    case dcmpg: case dcmpl:
301                        if (doubleValue(l) < doubleValue(r))
302                            return syms.intType.constType(minusOne);
303                        else if (doubleValue(l) > doubleValue(r))
304                            return syms.intType.constType(one);
305                        else if (doubleValue(l) == doubleValue(r))
306                            return syms.intType.constType(zero);
307                        else if (opcode == dcmpg)
308                            return syms.intType.constType(one);
309                        else
310                            return syms.intType.constType(minusOne);
311                    case if_acmpeq:
312                        return syms.booleanType.constType(b2i(l.equals(r)));
313                    case if_acmpne:
314                        return syms.booleanType.constType(b2i(!l.equals(r)));
315                    case string_add:
316                        return syms.stringType.constType(
317                            left.stringValue() + right.stringValue());
318                    default:
319                        return null;
320                    }
321                }
322            } catch (ArithmeticException e) {
323                return null;
324            }
325        }
326    
327        /** Coerce constant type to target type.
328         *  @param etype      The source type of the coercion,
329         *                    which is assumed to be a constant type compatble with
330         *                    ttype.
331         *  @param ttype      The target type of the coercion.
332         */
333         Type coerce(Type etype, Type ttype) {
334             // WAS if (etype.baseType() == ttype.baseType())
335             if (etype.tsym.type == ttype.tsym.type)
336                 return etype;
337             if (etype.tag <= DOUBLE) {
338                 Object n = etype.constValue();
339                 switch (ttype.tag) {
340                 case BYTE:
341                     return syms.byteType.constType(0 + (byte)intValue(n));
342                 case CHAR:
343                     return syms.charType.constType(0 + (char)intValue(n));
344                 case SHORT:
345                     return syms.shortType.constType(0 + (short)intValue(n));
346                 case INT:
347                     return syms.intType.constType(intValue(n));
348                 case LONG:
349                     return syms.longType.constType(longValue(n));
350                 case FLOAT:
351                     return syms.floatType.constType(floatValue(n));
352                 case DOUBLE:
353                     return syms.doubleType.constType(doubleValue(n));
354                 }
355             }
356             return ttype;
357         }
358    }