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.TryData;
032: import sun.tools.asm.CatchData;
033: import java.io.PrintStream;
034: import java.util.Enumeration;
035: import java.util.Hashtable;
036:
037: /**
038: * WARNING: The contents of this source file are not part of any
039: * supported API. Code that depends on them does so at its own risk:
040: * they are subject to change or removal without notice.
041: */
042: public class TryStatement extends Statement {
043: Statement body;
044: Statement args[];
045: long arrayCloneWhere; // private note posted from MethodExpression
046:
047: /**
048: * Constructor
049: */
050: public TryStatement(long where, Statement body, Statement args[]) {
051: super (TRY, where);
052: this .body = body;
053: this .args = args;
054: }
055:
056: /**
057: * Check statement
058: */
059: Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
060: checkLabel(env, ctx);
061: try {
062: vset = reach(env, vset);
063: Hashtable newexp = new Hashtable();
064: CheckContext newctx = new CheckContext(ctx, this );
065:
066: // Check 'try' block. A variable is DA (DU) before the try
067: // block if it is DA (DU) before the try statement.
068: Vset vs = body.check(env, newctx, vset.copy(), newexp);
069:
070: // A variable is DA before a catch block if it is DA before the
071: // try statement. A variable is DU before a catch block if it
072: // is DU after the try block and before any 'break', 'continue',
073: // 'throw', or 'return' contained therein. That is, the variable
074: // is DU upon entry to the try-statement and is not assigned to
075: // anywhere within the try block.
076: Vset cvs = Vset.firstDAandSecondDU(vset, vs.copy().join(
077: newctx.vsTryExit));
078:
079: for (int i = 0; i < args.length; i++) {
080: // A variable is DA (DU) after a try statement if
081: // it is DA (DU) after every catch block.
082: vs = vs.join(args[i]
083: .check(env, newctx, cvs.copy(), exp));
084: }
085:
086: // Check that catch statements are actually reached
087: for (int i = 1; i < args.length; i++) {
088: CatchStatement cs = (CatchStatement) args[i];
089: if (cs.field == null) {
090: continue;
091: }
092: Type type = cs.field.getType();
093: ClassDefinition def = env.getClassDefinition(type);
094:
095: for (int j = 0; j < i; j++) {
096: CatchStatement cs2 = (CatchStatement) args[j];
097: if (cs2.field == null) {
098: continue;
099: }
100: Type t = cs2.field.getType();
101: ClassDeclaration c = env.getClassDeclaration(t);
102: if (def.subClassOf(env, c)) {
103: env.error(args[i].where, "catch.not.reached");
104: break;
105: }
106: }
107: }
108:
109: ClassDeclaration ignore1 = env
110: .getClassDeclaration(idJavaLangError);
111: ClassDeclaration ignore2 = env
112: .getClassDeclaration(idJavaLangRuntimeException);
113:
114: // Make sure the exception is actually throw in that part of the code
115: for (int i = 0; i < args.length; i++) {
116: CatchStatement cs = (CatchStatement) args[i];
117: if (cs.field == null) {
118: continue;
119: }
120: Type type = cs.field.getType();
121: if (!type.isType(TC_CLASS)) {
122: // CatchStatement.checkValue() will have already printed
123: // an error message
124: continue;
125: }
126:
127: ClassDefinition def = env.getClassDefinition(type);
128:
129: // Anyone can throw these!
130: if (def.subClassOf(env, ignore1)
131: || def.super ClassOf(env, ignore1)
132: || def.subClassOf(env, ignore2)
133: || def.super ClassOf(env, ignore2)) {
134: continue;
135: }
136:
137: // Make sure the exception is actually throw in that part of the code
138: boolean ok = false;
139: for (Enumeration e = newexp.keys(); e.hasMoreElements();) {
140: ClassDeclaration c = (ClassDeclaration) e
141: .nextElement();
142: if (def.super ClassOf(env, c)
143: || def.subClassOf(env, c)) {
144: ok = true;
145: break;
146: }
147: }
148: if (!ok
149: && arrayCloneWhere != 0
150: && def.getName().toString().equals(
151: "java.lang.CloneNotSupportedException")) {
152: env
153: .error(arrayCloneWhere,
154: "warn.array.clone.supported", def
155: .getName());
156: }
157:
158: if (!ok) {
159: env.error(cs.where, "catch.not.thrown", def
160: .getName());
161: }
162: }
163:
164: // Only carry over exceptions that are not caught
165: for (Enumeration e = newexp.keys(); e.hasMoreElements();) {
166: ClassDeclaration c = (ClassDeclaration) e.nextElement();
167: ClassDefinition def = c.getClassDefinition(env);
168: boolean add = true;
169: for (int i = 0; i < args.length; i++) {
170: CatchStatement cs = (CatchStatement) args[i];
171: if (cs.field == null) {
172: continue;
173: }
174: Type type = cs.field.getType();
175: if (type.isType(TC_ERROR))
176: continue;
177: if (def.subClassOf(env, env
178: .getClassDeclaration(type))) {
179: add = false;
180: break;
181: }
182: }
183: if (add) {
184: exp.put(c, newexp.get(c));
185: }
186: }
187: // A variable is DA (DU) after a try statement if it is DA (DU)
188: // after the try block and after every catch block. These variables
189: // are represented by 'vs'. If the try statement is labelled, we
190: // may also exit from it (including from within a catch block) via
191: // a break statement.
192: // If there is a finally block, the Vset returned here is further
193: // adjusted. Note that this 'TryStatement' node will be a child of
194: // a 'FinallyStatement' node in that case.
195: return ctx.removeAdditionalVars(vs.join(newctx.vsBreak));
196: } catch (ClassNotFound e) {
197: env.error(where, "class.not.found", e.name, opNames[op]);
198: return vset;
199: }
200: }
201:
202: /**
203: * Inline
204: */
205: public Statement inline(Environment env, Context ctx) {
206: if (body != null) {
207: body = body.inline(env, new Context(ctx, this ));
208: }
209: if (body == null) {
210: return null;
211: }
212: for (int i = 0; i < args.length; i++) {
213: if (args[i] != null) {
214: args[i] = args[i].inline(env, new Context(ctx, this ));
215: }
216: }
217: return (args.length == 0) ? eliminate(env, body) : this ;
218: }
219:
220: /**
221: * Create a copy of the statement for method inlining
222: */
223: public Statement copyInline(Context ctx, boolean valNeeded) {
224: TryStatement s = (TryStatement) clone();
225: if (body != null) {
226: s.body = body.copyInline(ctx, valNeeded);
227: }
228: s.args = new Statement[args.length];
229: for (int i = 0; i < args.length; i++) {
230: if (args[i] != null) {
231: s.args[i] = args[i].copyInline(ctx, valNeeded);
232: }
233: }
234: return s;
235: }
236:
237: /**
238: * Compute cost of inlining this statement
239: */
240: public int costInline(int thresh, Environment env, Context ctx) {
241:
242: // Don't inline methods containing try statements.
243: // If the try statement is being inlined in order to
244: // inline a method that returns a value which is
245: // a subexpression of an expression involving the
246: // operand stack, then the early operands may get lost.
247: // This shows up as a verifier error. For example,
248: // in the following:
249: //
250: // public static int test() {
251: // try { return 2; } catch (Exception e) { return 0; }
252: // }
253: //
254: // System.out.println(test());
255: //
256: // an inlined call to test() might look like this:
257: //
258: // 0 getstatic <Field java.io.PrintStream out>
259: // 3 iconst_2
260: // 4 goto 9
261: // 7 pop
262: // 8 iconst_0
263: // 9 invokevirtual <Method void println(int)>
264: // 12 return
265: // Exception table:
266: // from to target type
267: // 3 7 7 <Class java.lang.Exception>
268: //
269: // This fails to verify because the operand stored
270: // for System.out gets axed at an exception, leading to
271: // an inconsistent stack depth at pc=7.
272: //
273: // Note that although all code must be able to be inlined
274: // to implement initializers, this problem doesn't come up,
275: // as try statements themselves can never be expressions.
276: // It suffices here to make sure they are never inlined as part
277: // of optimization.
278:
279: return thresh;
280: }
281:
282: /**
283: * Code
284: */
285: public void code(Environment env, Context ctx, Assembler asm) {
286: CodeContext newctx = new CodeContext(ctx, this );
287:
288: TryData td = new TryData();
289: for (int i = 0; i < args.length; i++) {
290: Type t = ((CatchStatement) args[i]).field.getType();
291: if (t.isType(TC_CLASS)) {
292: td.add(env.getClassDeclaration(t));
293: } else {
294: td.add(t);
295: }
296: }
297: asm.add(where, opc_try, td);
298: if (body != null) {
299: body.code(env, newctx, asm);
300: }
301:
302: asm.add(td.getEndLabel());
303: asm.add(where, opc_goto, newctx.breakLabel);
304:
305: for (int i = 0; i < args.length; i++) {
306: CatchData cd = td.getCatch(i);
307: asm.add(cd.getLabel());
308: args[i].code(env, newctx, asm);
309: asm.add(where, opc_goto, newctx.breakLabel);
310: }
311:
312: asm.add(newctx.breakLabel);
313: }
314:
315: /**
316: * Print
317: */
318: public void print(PrintStream out, int indent) {
319: super .print(out, indent);
320: out.print("try ");
321: if (body != null) {
322: body.print(out, indent);
323: } else {
324: out.print("<empty>");
325: }
326: for (int i = 0; i < args.length; i++) {
327: out.print(" ");
328: args[i].print(out, indent);
329: }
330: }
331: }
|