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      */
ConditionalExpression(long where, Expression cond, Expression left, Expression right)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      */
order()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      */
checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)67     public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> 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 
check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)110     public Vset check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> 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      */
isConstant()119     public boolean isConstant() {
120         return cond.isConstant() && left.isConstant() && right.isConstant();
121     }
122 
123     /**
124      * Simplify
125      */
simplify()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      */
inline(Environment env, Context ctx)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 
inlineValue(Environment env, Context ctx)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      */
costInline(int thresh, Environment env, Context ctx)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      */
copyInline(Context ctx)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      */
codeValue(Environment env, Context ctx, Assembler asm)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     }
code(Environment env, Context ctx, Assembler asm)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      */
print(PrintStream out)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 }
236