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
26package sun.tools.tree;
27
28import sun.tools.java.*;
29import sun.tools.asm.Assembler;
30import sun.tools.asm.Label;
31import java.io.PrintStream;
32import 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 */
39public
40class 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<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
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     */
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}
236