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: @Version("@(#)ConstFold.java 1.35 07/05/05")
046: strictfp class ConstFold {
047: protected static final Context.Key<ConstFold> constFoldKey = 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:
074: private static int intValue(Object x) {
075: return ((Number) x).intValue();
076: }
077:
078: private static long longValue(Object x) {
079: return ((Number) x).longValue();
080: }
081:
082: private static float floatValue(Object x) {
083: return ((Number) x).floatValue();
084: }
085:
086: private static double doubleValue(Object x) {
087: return ((Number) x).doubleValue();
088: }
089:
090: /** Fold binary or unary operation, returning constant type reflecting the
091: * operations result. Return null if fold failed due to an
092: * arithmetic exception.
093: * @param opcode The operation's opcode instruction (usually a byte code),
094: * as entered by class Symtab.
095: * @param argtypes The operation's argument types (a list of length 1 or 2).
096: * Argument types are assumed to have non-null constValue's.
097: */
098: Type fold(int opcode, List<Type> argtypes) {
099: int argCount = argtypes.length();
100: if (argCount == 1)
101: return fold1(opcode, argtypes.head);
102: else if (argCount == 2)
103: return fold2(opcode, argtypes.head, argtypes.tail.head);
104: else
105: throw new AssertionError();
106: }
107:
108: /** Fold unary operation.
109: * @param opcode The operation's opcode instruction (usually a byte code),
110: * as entered by class Symtab.
111: * opcode's ifeq to ifge are for postprocessing
112: * xcmp; ifxx pairs of instructions.
113: * @param operand The operation's operand type.
114: * Argument types are assumed to have non-null constValue's.
115: */
116: Type fold1(int opcode, Type operand) {
117: try {
118: Object od = operand.constValue();
119: switch (opcode) {
120: case nop:
121: return operand;
122: case ineg: // unary -
123: return syms.intType.constType(-intValue(od));
124: case ixor: // ~
125: return syms.intType.constType(~intValue(od));
126: case bool_not: // !
127: return syms.booleanType
128: .constType(b2i(intValue(od) == 0));
129: case ifeq:
130: return syms.booleanType
131: .constType(b2i(intValue(od) == 0));
132: case ifne:
133: return syms.booleanType
134: .constType(b2i(intValue(od) != 0));
135: case iflt:
136: return syms.booleanType
137: .constType(b2i(intValue(od) < 0));
138: case ifgt:
139: return syms.booleanType
140: .constType(b2i(intValue(od) > 0));
141: case ifle:
142: return syms.booleanType
143: .constType(b2i(intValue(od) <= 0));
144: case ifge:
145: return syms.booleanType
146: .constType(b2i(intValue(od) >= 0));
147:
148: case lneg: // unary -
149: return syms.longType
150: .constType(new Long(-longValue(od)));
151: case lxor: // ~
152: return syms.longType
153: .constType(new Long(~longValue(od)));
154:
155: case fneg: // unary -
156: return syms.floatType.constType(new Float(
157: -floatValue(od)));
158:
159: case dneg: // ~
160: return syms.doubleType.constType(new Double(
161: -doubleValue(od)));
162:
163: default:
164: return null;
165: }
166: } catch (ArithmeticException e) {
167: return null;
168: }
169: }
170:
171: /** Fold binary operation.
172: * @param opcode The operation's opcode instruction (usually a byte code),
173: * as entered by class Symtab.
174: * opcode's ifeq to ifge are for postprocessing
175: * xcmp; ifxx pairs of instructions.
176: * @param left The type of the operation's left operand.
177: * @param right The type of the operation's right operand.
178: */
179: Type fold2(int opcode, Type left, Type right) {
180: try {
181: if (opcode > ByteCodes.preMask) {
182: // we are seeing a composite instruction of the form xcmp; ifxx.
183: // In this case fold both instructions separately.
184: Type t1 = fold2(opcode >> ByteCodes.preShift, left,
185: right);
186: return (t1.constValue() == null) ? t1 : fold1(opcode
187: & ByteCodes.preMask, t1);
188: } else {
189: Object l = left.constValue();
190: Object r = right.constValue();
191: switch (opcode) {
192: case iadd:
193: return syms.intType.constType(intValue(l)
194: + intValue(r));
195: case isub:
196: return syms.intType.constType(intValue(l)
197: - intValue(r));
198: case imul:
199: return syms.intType.constType(intValue(l)
200: * intValue(r));
201: case idiv:
202: return syms.intType.constType(intValue(l)
203: / intValue(r));
204: case imod:
205: return syms.intType.constType(intValue(l)
206: % intValue(r));
207: case iand:
208: return (left.tag == BOOLEAN ? syms.booleanType
209: : syms.intType).constType(intValue(l)
210: & intValue(r));
211: case bool_and:
212: return syms.booleanType
213: .constType(b2i((intValue(l) & intValue(r)) != 0));
214: case ior:
215: return (left.tag == BOOLEAN ? syms.booleanType
216: : syms.intType).constType(intValue(l)
217: | intValue(r));
218: case bool_or:
219: return syms.booleanType
220: .constType(b2i((intValue(l) | intValue(r)) != 0));
221: case ixor:
222: return (left.tag == BOOLEAN ? syms.booleanType
223: : syms.intType).constType(intValue(l)
224: ^ intValue(r));
225: case ishl:
226: case ishll:
227: return syms.intType
228: .constType(intValue(l) << intValue(r));
229: case ishr:
230: case ishrl:
231: return syms.intType
232: .constType(intValue(l) >> intValue(r));
233: case iushr:
234: case iushrl:
235: return syms.intType
236: .constType(intValue(l) >>> intValue(r));
237: case if_icmpeq:
238: return syms.booleanType
239: .constType(b2i(intValue(l) == intValue(r)));
240: case if_icmpne:
241: return syms.booleanType
242: .constType(b2i(intValue(l) != intValue(r)));
243: case if_icmplt:
244: return syms.booleanType
245: .constType(b2i(intValue(l) < intValue(r)));
246: case if_icmpgt:
247: return syms.booleanType
248: .constType(b2i(intValue(l) > intValue(r)));
249: case if_icmple:
250: return syms.booleanType
251: .constType(b2i(intValue(l) <= intValue(r)));
252: case if_icmpge:
253: return syms.booleanType
254: .constType(b2i(intValue(l) >= intValue(r)));
255:
256: case ladd:
257: return syms.longType.constType(new Long(
258: longValue(l) + longValue(r)));
259: case lsub:
260: return syms.longType.constType(new Long(
261: longValue(l) - longValue(r)));
262: case lmul:
263: return syms.longType.constType(new Long(
264: longValue(l) * longValue(r)));
265: case ldiv:
266: return syms.longType.constType(new Long(
267: longValue(l) / longValue(r)));
268: case lmod:
269: return syms.longType.constType(new Long(
270: longValue(l) % longValue(r)));
271: case land:
272: return syms.longType.constType(new Long(
273: longValue(l) & longValue(r)));
274: case lor:
275: return syms.longType.constType(new Long(
276: longValue(l) | longValue(r)));
277: case lxor:
278: return syms.longType.constType(new Long(
279: longValue(l) ^ longValue(r)));
280: case lshl:
281: case lshll:
282: return syms.longType.constType(new Long(
283: longValue(l) << intValue(r)));
284: case lshr:
285: case lshrl:
286: return syms.longType.constType(new Long(
287: longValue(l) >> intValue(r)));
288: case lushr:
289: return syms.longType.constType(new Long(
290: longValue(l) >>> intValue(r)));
291: case lcmp:
292: if (longValue(l) < longValue(r))
293: return syms.intType.constType(minusOne);
294: else if (longValue(l) > longValue(r))
295: return syms.intType.constType(one);
296: else
297: return syms.intType.constType(zero);
298: case fadd:
299: return syms.floatType.constType(new Float(
300: floatValue(l) + floatValue(r)));
301: case fsub:
302: return syms.floatType.constType(new Float(
303: floatValue(l) - floatValue(r)));
304: case fmul:
305: return syms.floatType.constType(new Float(
306: floatValue(l) * floatValue(r)));
307: case fdiv:
308: return syms.floatType.constType(new Float(
309: floatValue(l) / floatValue(r)));
310: case fmod:
311: return syms.floatType.constType(new Float(
312: floatValue(l) % floatValue(r)));
313: case fcmpg:
314: case fcmpl:
315: if (floatValue(l) < floatValue(r))
316: return syms.intType.constType(minusOne);
317: else if (floatValue(l) > floatValue(r))
318: return syms.intType.constType(one);
319: else if (floatValue(l) == floatValue(r))
320: return syms.intType.constType(zero);
321: else if (opcode == fcmpg)
322: return syms.intType.constType(one);
323: else
324: return syms.intType.constType(minusOne);
325: case dadd:
326: return syms.doubleType.constType(new Double(
327: doubleValue(l) + doubleValue(r)));
328: case dsub:
329: return syms.doubleType.constType(new Double(
330: doubleValue(l) - doubleValue(r)));
331: case dmul:
332: return syms.doubleType.constType(new Double(
333: doubleValue(l) * doubleValue(r)));
334: case ddiv:
335: return syms.doubleType.constType(new Double(
336: doubleValue(l) / doubleValue(r)));
337: case dmod:
338: return syms.doubleType.constType(new Double(
339: doubleValue(l) % doubleValue(r)));
340: case dcmpg:
341: case dcmpl:
342: if (doubleValue(l) < doubleValue(r))
343: return syms.intType.constType(minusOne);
344: else if (doubleValue(l) > doubleValue(r))
345: return syms.intType.constType(one);
346: else if (doubleValue(l) == doubleValue(r))
347: return syms.intType.constType(zero);
348: else if (opcode == dcmpg)
349: return syms.intType.constType(one);
350: else
351: return syms.intType.constType(minusOne);
352: case if_acmpeq:
353: return syms.booleanType.constType(b2i(l.equals(r)));
354: case if_acmpne:
355: return syms.booleanType
356: .constType(b2i(!l.equals(r)));
357: case string_add:
358: return syms.stringType.constType(left.stringValue()
359: + right.stringValue());
360: default:
361: return null;
362: }
363: }
364: } catch (ArithmeticException e) {
365: return null;
366: }
367: }
368:
369: /** Coerce constant type to target type.
370: * @param etype The source type of the coercion,
371: * which is assumed to be a constant type compatble with
372: * ttype.
373: * @param ttype The target type of the coercion.
374: */
375: Type coerce(Type etype, Type ttype) {
376: // WAS if (etype.baseType() == ttype.baseType())
377: if (etype.tsym.type == ttype.tsym.type)
378: return etype;
379: if (etype.tag <= DOUBLE) {
380: Object n = etype.constValue();
381: switch (ttype.tag) {
382: case BYTE:
383: return syms.byteType.constType(0 + (byte) intValue(n));
384: case CHAR:
385: return syms.charType.constType(0 + (char) intValue(n));
386: case SHORT:
387: return syms.shortType
388: .constType(0 + (short) intValue(n));
389: case INT:
390: return syms.intType.constType(intValue(n));
391: case LONG:
392: return syms.longType.constType(longValue(n));
393: case FLOAT:
394: return syms.floatType.constType(floatValue(n));
395: case DOUBLE:
396: return syms.doubleType.constType(doubleValue(n));
397: }
398: }
399: return ttype;
400: }
401: }
|