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 sun.tools.asm.SwitchData;
032: import java.io.PrintStream;
033: import java.util.Hashtable;
034:
035: /**
036: * WARNING: The contents of this source file are not part of any
037: * supported API. Code that depends on them does so at its own risk:
038: * they are subject to change or removal without notice.
039: */
040: public class SwitchStatement extends Statement {
041: Expression expr;
042: Statement args[];
043:
044: /**
045: * Constructor
046: */
047: public SwitchStatement(long where, Expression expr,
048: Statement args[]) {
049: super (SWITCH, where);
050: this .expr = expr;
051: this .args = args;
052: }
053:
054: /**
055: * Check statement
056: */
057: Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
058: checkLabel(env, ctx);
059: CheckContext newctx = new CheckContext(ctx, this );
060: vset = expr.checkValue(env, newctx, reach(env, vset), exp);
061: Type switchType = expr.type;
062:
063: expr = convert(env, newctx, Type.tInt, expr);
064:
065: Hashtable tab = new Hashtable();
066: boolean hasDefault = false;
067: // Note that vs is reset to vset.copy() on every case label.
068: // If the first substatement is not a case label, it is unreached.
069: Vset vs = DEAD_END;
070:
071: for (int i = 0; i < args.length; i++) {
072: Statement s = args[i];
073:
074: if (s.op == CASE) {
075:
076: vs = s.check(env, newctx, vs.join(vset.copy()), exp);
077:
078: Expression lbl = ((CaseStatement) s).expr;
079: if (lbl != null) {
080: if (lbl instanceof IntegerExpression) {
081: Integer Ivalue = (Integer) (((IntegerExpression) lbl)
082: .getValue());
083: int ivalue = Ivalue.intValue();
084: if (tab.get(lbl) != null) {
085: env.error(s.where, "duplicate.label",
086: Ivalue);
087: } else {
088: tab.put(lbl, s);
089: boolean overflow;
090: switch (switchType.getTypeCode()) {
091: case TC_BYTE:
092: overflow = (ivalue != (byte) ivalue);
093: break;
094: case TC_SHORT:
095: overflow = (ivalue != (short) ivalue);
096: break;
097: case TC_CHAR:
098: overflow = (ivalue != (char) ivalue);
099: break;
100: default:
101: overflow = false;
102: }
103: if (overflow) {
104: env.error(s.where, "switch.overflow",
105: Ivalue, switchType);
106: }
107: }
108: } else {
109: // Suppose a class got an error early on during
110: // checking. It will set all of its members to
111: // have the status "ERROR". Now suppose that a
112: // case label refers to one of this class's
113: // fields. When we check the case label, the
114: // compiler will try to inline the FieldExpression.
115: // Since the expression has ERROR status, it doesn't
116: // inline. This means that instead of the case
117: // label being an IntegerExpression, it will still
118: // be a FieldExpression, and we will end up in this
119: // else block. So, before we just assume that
120: // the expression isn't constant, do a check to
121: // see if it was constant but unable to inline.
122: // This eliminates some spurious error messages.
123: // (Bug id 4067498).
124: if (!lbl.isConstant()
125: || lbl.getType() != Type.tInt) {
126: env.error(s.where, "const.expr.required");
127: }
128: }
129: } else {
130: if (hasDefault) {
131: env.error(s.where, "duplicate.default");
132: }
133: hasDefault = true;
134: }
135: } else {
136: vs = s.checkBlockStatement(env, newctx, vs, exp);
137: }
138: }
139: if (!vs.isDeadEnd()) {
140: newctx.vsBreak = newctx.vsBreak.join(vs);
141: }
142: if (hasDefault)
143: vset = newctx.vsBreak;
144: return ctx.removeAdditionalVars(vset);
145: }
146:
147: /**
148: * Inline
149: */
150: public Statement inline(Environment env, Context ctx) {
151: ctx = new Context(ctx, this );
152: expr = expr.inlineValue(env, ctx);
153: for (int i = 0; i < args.length; i++) {
154: if (args[i] != null) {
155: args[i] = args[i].inline(env, ctx);
156: }
157: }
158: return this ;
159: }
160:
161: /**
162: * Create a copy of the statement for method inlining
163: */
164: public Statement copyInline(Context ctx, boolean valNeeded) {
165: SwitchStatement s = (SwitchStatement) clone();
166: s.expr = expr.copyInline(ctx);
167: s.args = new Statement[args.length];
168: for (int i = 0; i < args.length; i++) {
169: if (args[i] != null) {
170: s.args[i] = args[i].copyInline(ctx, valNeeded);
171: }
172: }
173: return s;
174: }
175:
176: /**
177: * The cost of inlining this statement
178: */
179: public int costInline(int thresh, Environment env, Context ctx) {
180: int cost = expr.costInline(thresh, env, ctx);
181: for (int i = 0; (i < args.length) && (cost < thresh); i++) {
182: if (args[i] != null) {
183: cost += args[i].costInline(thresh, env, ctx);
184: }
185: }
186: return cost;
187: }
188:
189: /**
190: * Code
191: */
192: public void code(Environment env, Context ctx, Assembler asm) {
193: CodeContext newctx = new CodeContext(ctx, this );
194:
195: expr.codeValue(env, newctx, asm);
196:
197: SwitchData sw = new SwitchData();
198: boolean hasDefault = false;
199:
200: for (int i = 0; i < args.length; i++) {
201: Statement s = args[i];
202: if ((s != null) && (s.op == CASE)) {
203: Expression e = ((CaseStatement) s).expr;
204: if (e != null) {
205: sw.add(((IntegerExpression) e).value, new Label());
206: }
207: // JCOV
208: else {
209: hasDefault = true;
210: }
211: // end JCOV
212: }
213: }
214:
215: // JCOV
216: if (env.coverage())
217: sw.initTableCase();
218: // end JCOV
219: asm.add(where, opc_tableswitch, sw);
220:
221: for (int i = 0; i < args.length; i++) {
222: Statement s = args[i];
223: if (s != null) {
224: if (s.op == CASE) {
225: Expression e = ((CaseStatement) s).expr;
226: if (e != null) {
227: asm.add(sw.get(((IntegerExpression) e).value));
228: // JCOV
229: sw.addTableCase(((IntegerExpression) e).value,
230: s.where);
231: // end JCOV
232: } else {
233: asm.add(sw.getDefaultLabel());
234: // JCOV
235: sw.addTableDefault(s.where);
236: // end JCOV
237: /* JCOV hasDefault = true; end JCOV */
238: }
239: } else {
240: s.code(env, newctx, asm);
241: }
242: }
243: }
244:
245: if (!hasDefault) {
246: asm.add(sw.getDefaultLabel());
247: }
248: asm.add(newctx.breakLabel);
249: }
250:
251: /**
252: * Print
253: */
254: public void print(PrintStream out, int indent) {
255: super .print(out, indent);
256: out.print("switch (");
257: expr.print(out);
258: out.print(") {\n");
259: for (int i = 0; i < args.length; i++) {
260: if (args[i] != null) {
261: printIndent(out, indent + 1);
262: args[i].print(out, indent + 1);
263: out.print("\n");
264: }
265: }
266: printIndent(out, indent);
267: out.print("}");
268: }
269: }
|