001: /*
002: * Copyright 1994-2003 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 sun.tools.tree;
027:
028: import sun.tools.java.*;
029: import sun.tools.asm.Assembler;
030: import sun.tools.asm.Label;
031: import java.io.PrintStream;
032: import java.util.Hashtable;
033:
034: /**
035: * WARNING: The contents of this source file are not part of any
036: * supported API. Code that depends on them does so at its own risk:
037: * they are subject to change or removal without notice.
038: */
039: public class ConditionalExpression extends BinaryExpression {
040: Expression cond;
041:
042: /**
043: * Constructor
044: */
045: public ConditionalExpression(long where, Expression cond,
046: Expression left, Expression right) {
047: super (COND, where, Type.tError, left, right);
048: this .cond = cond;
049: }
050:
051: /**
052: * Order the expression based on precedence
053: */
054: public Expression order() {
055: if (precedence() > cond.precedence()) {
056: UnaryExpression e = (UnaryExpression) cond;
057: cond = e.right;
058: e.right = order();
059: return e;
060: }
061: return this ;
062: }
063:
064: /**
065: * Check the expression
066: */
067: public Vset checkValue(Environment env, Context ctx, Vset vset,
068: Hashtable exp) {
069: ConditionVars cvars = cond.checkCondition(env, ctx, vset, exp);
070: vset = left.checkValue(env, ctx, cvars.vsTrue, exp).join(
071: right.checkValue(env, ctx, cvars.vsFalse, exp));
072: cond = convert(env, ctx, Type.tBoolean, cond);
073:
074: int tm = left.type.getTypeMask() | right.type.getTypeMask();
075: if ((tm & TM_ERROR) != 0) {
076: type = Type.tError;
077: return vset;
078: }
079: if (left.type.equals(right.type)) {
080: type = left.type;
081: } else if ((tm & TM_DOUBLE) != 0) {
082: type = Type.tDouble;
083: } else if ((tm & TM_FLOAT) != 0) {
084: type = Type.tFloat;
085: } else if ((tm & TM_LONG) != 0) {
086: type = Type.tLong;
087: } else if ((tm & TM_REFERENCE) != 0) {
088: try {
089: // This is wrong. We should be using their most common
090: // ancestor, instead.
091: type = env.implicitCast(right.type, left.type) ? left.type
092: : right.type;
093: } catch (ClassNotFound e) {
094: type = Type.tError;
095: }
096: } else if (((tm & TM_CHAR) != 0)
097: && left.fitsType(env, ctx, Type.tChar)
098: && right.fitsType(env, ctx, Type.tChar)) {
099: type = Type.tChar;
100: } else if (((tm & TM_SHORT) != 0)
101: && left.fitsType(env, ctx, Type.tShort)
102: && right.fitsType(env, ctx, Type.tShort)) {
103: type = Type.tShort;
104: } else if (((tm & TM_BYTE) != 0)
105: && left.fitsType(env, ctx, Type.tByte)
106: && right.fitsType(env, ctx, Type.tByte)) {
107: type = Type.tByte;
108: } else {
109: type = Type.tInt;
110: }
111:
112: left = convert(env, ctx, type, left);
113: right = convert(env, ctx, type, right);
114: return vset;
115: }
116:
117: public Vset check(Environment env, Context ctx, Vset vset,
118: Hashtable exp) {
119: vset = cond.checkValue(env, ctx, vset, exp);
120: cond = convert(env, ctx, Type.tBoolean, cond);
121: return left.check(env, ctx, vset.copy(), exp).join(
122: right.check(env, ctx, vset, exp));
123: }
124:
125: /**
126: * Check if constant
127: */
128: public boolean isConstant() {
129: return cond.isConstant() && left.isConstant()
130: && right.isConstant();
131: }
132:
133: /**
134: * Simplify
135: */
136: Expression simplify() {
137: if (cond.equals(true)) {
138: return left;
139: }
140: if (cond.equals(false)) {
141: return right;
142: }
143: return this ;
144: }
145:
146: /**
147: * Inline
148: */
149: public Expression inline(Environment env, Context ctx) {
150: left = left.inline(env, ctx);
151: right = right.inline(env, ctx);
152: if ((left == null) && (right == null)) {
153: return cond.inline(env, ctx);
154: }
155: if (left == null) {
156: left = right;
157: right = null;
158: cond = new NotExpression(where, cond);
159: }
160: cond = cond.inlineValue(env, ctx);
161: return simplify();
162: }
163:
164: public Expression inlineValue(Environment env, Context ctx) {
165: cond = cond.inlineValue(env, ctx);
166: left = left.inlineValue(env, ctx);
167: right = right.inlineValue(env, ctx);
168: return simplify();
169: }
170:
171: /**
172: * The cost of inlining this expression
173: */
174: public int costInline(int thresh, Environment env, Context ctx) {
175: // We need to check if right is null in case costInline()
176: // is called after this expression has been inlined.
177: // This call can happen, for example, in MemberDefinition#cleanup().
178: // (Fix for 4069861).
179: return 1
180: + cond.costInline(thresh, env, ctx)
181: + left.costInline(thresh, env, ctx)
182: + ((right == null) ? 0 : right.costInline(thresh, env,
183: ctx));
184: }
185:
186: /**
187: * Create a copy of the expression for method inlining
188: */
189: public Expression copyInline(Context ctx) {
190: ConditionalExpression e = (ConditionalExpression) clone();
191: e.cond = cond.copyInline(ctx);
192: e.left = left.copyInline(ctx);
193:
194: // If copyInline() is called after inlining is complete,
195: // right could be null.
196: e.right = (right == null) ? null : right.copyInline(ctx);
197:
198: return e;
199: }
200:
201: /**
202: * Code
203: */
204: public void codeValue(Environment env, Context ctx, Assembler asm) {
205: Label l1 = new Label();
206: Label l2 = new Label();
207:
208: cond.codeBranch(env, ctx, asm, l1, false);
209: left.codeValue(env, ctx, asm);
210: asm.add(where, opc_goto, l2);
211: asm.add(l1);
212: right.codeValue(env, ctx, asm);
213: asm.add(l2);
214: }
215:
216: public void code(Environment env, Context ctx, Assembler asm) {
217: Label l1 = new Label();
218: cond.codeBranch(env, ctx, asm, l1, false);
219: left.code(env, ctx, asm);
220: if (right != null) {
221: Label l2 = new Label();
222: asm.add(where, opc_goto, l2);
223: asm.add(l1);
224: right.code(env, ctx, asm);
225: asm.add(l2);
226: } else {
227: asm.add(l1);
228: }
229: }
230:
231: /**
232: * Print
233: */
234: public void print(PrintStream out) {
235: out.print("(" + opNames[op] + " ");
236: cond.print(out);
237: out.print(" ");
238: left.print(out);
239: out.print(" ");
240: if (right != null) {
241: right.print(out);
242: } else {
243: out.print("<null>");
244: }
245: out.print(")");
246: }
247: }
|