View Javadoc
1   /*
2    * Copyright (c) 1994, 2003, 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 sun.tools.tree;
27  
28  import sun.tools.java.*;
29  import sun.tools.asm.Assembler;
30  import sun.tools.asm.Label;
31  import java.io.PrintStream;
32  import java.util.Hashtable;
33  
34  /**
35   * WARNING: The contents of this source file are not part of any
36   * supported API.  Code that depends on them does so at its own risk:
37   * they are subject to change or removal without notice.
38   */
39  public
40  class ConditionalExpression extends BinaryExpression {
41      Expression cond;
42  
43      /**
44       * Constructor
45       */
46      public ConditionalExpression(long where, Expression cond, Expression left, Expression right) {
47          super(COND, where, Type.tError, left, right);
48          this.cond = cond;
49      }
50  
51      /**
52       * Order the expression based on precedence
53       */
54      public Expression order() {
55          if (precedence() > cond.precedence()) {
56              UnaryExpression e = (UnaryExpression)cond;
57              cond = e.right;
58              e.right = order();
59              return e;
60          }
61          return this;
62      }
63  
64      /**
65       * Check the expression
66       */
67      public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) {
68          ConditionVars cvars = cond.checkCondition(env, ctx, vset, exp);
69          vset = left.checkValue(env, ctx, cvars.vsTrue, exp).join(
70                 right.checkValue(env, ctx, cvars.vsFalse, exp) );
71          cond = convert(env, ctx, Type.tBoolean, cond);
72  
73          int tm = left.type.getTypeMask() | right.type.getTypeMask();
74          if ((tm & TM_ERROR) != 0) {
75              type = Type.tError;
76              return vset;
77          }
78          if (left.type.equals(right.type)) {
79              type = left.type;
80          } else if ((tm & TM_DOUBLE) != 0) {
81              type = Type.tDouble;
82          } else if ((tm & TM_FLOAT) != 0) {
83              type = Type.tFloat;
84          } else if ((tm & TM_LONG) != 0) {
85              type = Type.tLong;
86          } else if ((tm & TM_REFERENCE) != 0) {
87              try {
88                  // This is wrong.  We should be using their most common
89                  // ancestor, instead.
90                  type = env.implicitCast(right.type, left.type)
91                      ? left.type : right.type;
92              } catch (ClassNotFound e) {
93                  type = Type.tError;
94              }
95          } else if (((tm & TM_CHAR) != 0) && left.fitsType(env, ctx, Type.tChar) && right.fitsType(env, ctx, Type.tChar)) {
96              type = Type.tChar;
97          } else if (((tm & TM_SHORT) != 0) && left.fitsType(env, ctx, Type.tShort) && right.fitsType(env, ctx, Type.tShort)) {
98              type = Type.tShort;
99          } else if (((tm & TM_BYTE) != 0) && left.fitsType(env, ctx, Type.tByte) && right.fitsType(env, ctx, Type.tByte)) {
100             type = Type.tByte;
101         } else {
102             type = Type.tInt;
103         }
104 
105         left = convert(env, ctx, type, left);
106         right = convert(env, ctx, type, right);
107         return vset;
108     }
109 
110     public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
111         vset = cond.checkValue(env, ctx, vset, exp);
112         cond = convert(env, ctx, Type.tBoolean, cond);
113         return left.check(env, ctx, vset.copy(), exp).join(right.check(env, ctx, vset, exp));
114     }
115 
116     /**
117      * Check if constant
118      */
119     public boolean isConstant() {
120         return cond.isConstant() && left.isConstant() && right.isConstant();
121     }
122 
123     /**
124      * Simplify
125      */
126     Expression simplify() {
127         if (cond.equals(true)) {
128             return left;
129         }
130         if (cond.equals(false)) {
131             return right;
132         }
133         return this;
134     }
135 
136     /**
137      * Inline
138      */
139     public Expression inline(Environment env, Context ctx) {
140         left = left.inline(env, ctx);
141         right = right.inline(env, ctx);
142         if ((left == null) && (right == null)) {
143             return cond.inline(env, ctx);
144         }
145         if (left == null) {
146             left = right;
147             right = null;
148             cond = new NotExpression(where, cond);
149         }
150         cond = cond.inlineValue(env, ctx);
151         return simplify();
152     }
153 
154     public Expression inlineValue(Environment env, Context ctx) {
155         cond = cond.inlineValue(env, ctx);
156         left = left.inlineValue(env, ctx);
157         right = right.inlineValue(env, ctx);
158         return simplify();
159     }
160 
161     /**
162      * The cost of inlining this expression
163      */
164     public int costInline(int thresh, Environment env, Context ctx) {
165         // We need to check if right is null in case costInline()
166         // is called after this expression has been inlined.
167         // This call can happen, for example, in MemberDefinition#cleanup().
168         // (Fix for 4069861).
169         return 1 +
170             cond.costInline(thresh, env, ctx) +
171             left.costInline(thresh, env, ctx) +
172             ((right == null) ? 0 : right.costInline(thresh, env, ctx));
173     }
174 
175     /**
176      * Create a copy of the expression for method inlining
177      */
178     public Expression copyInline(Context ctx) {
179         ConditionalExpression e = (ConditionalExpression)clone();
180         e.cond = cond.copyInline(ctx);
181         e.left = left.copyInline(ctx);
182 
183         // If copyInline() is called after inlining is complete,
184         // right could be null.
185         e.right = (right == null) ? null : right.copyInline(ctx);
186 
187         return e;
188     }
189 
190     /**
191      * Code
192      */
193     public void codeValue(Environment env, Context ctx, Assembler asm) {
194         Label l1 = new Label();
195         Label l2 = new Label();
196 
197         cond.codeBranch(env, ctx, asm, l1, false);
198         left.codeValue(env, ctx, asm);
199         asm.add(where, opc_goto, l2);
200         asm.add(l1);
201         right.codeValue(env, ctx, asm);
202         asm.add(l2);
203     }
204     public void code(Environment env, Context ctx, Assembler asm) {
205         Label l1 = new Label();
206         cond.codeBranch(env, ctx, asm, l1, false);
207         left.code(env, ctx, asm);
208         if (right != null) {
209             Label l2 = new Label();
210             asm.add(where, opc_goto, l2);
211             asm.add(l1);
212             right.code(env, ctx, asm);
213             asm.add(l2);
214         } else {
215             asm.add(l1);
216         }
217     }
218 
219     /**
220      * Print
221      */
222     public void print(PrintStream out) {
223         out.print("(" + opNames[op] + " ");
224         cond.print(out);
225         out.print(" ");
226         left.print(out);
227         out.print(" ");
228         if (right != null) {
229             right.print(out);
230         } else {
231             out.print("<null>");
232         }
233         out.print(")");
234     }
235 }