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 sun.tools.asm.TryData;
32 import sun.tools.asm.CatchData;
33 import java.io.PrintStream;
34 import java.util.Enumeration;
35 import java.util.Hashtable;
36 
37 /**
38  * WARNING: The contents of this source file are not part of any
39  * supported API.  Code that depends on them does so at its own risk:
40  * they are subject to change or removal without notice.
41  */
42 public
43 class TryStatement extends Statement {
44     Statement body;
45     Statement args[];
46     long arrayCloneWhere;       // private note posted from MethodExpression
47 
48     /**
49      * Constructor
50      */
TryStatement(long where, Statement body, Statement args[])51     public TryStatement(long where, Statement body, Statement args[]) {
52         super(TRY, where);
53         this.body = body;
54         this.args = args;
55     }
56 
57     /**
58      * Check statement
59      */
check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)60     Vset check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp) {
61         checkLabel(env, ctx);
62         try {
63             vset = reach(env, vset);
64             Hashtable<Object, Object> newexp = new Hashtable<>();
65             CheckContext newctx =  new CheckContext(ctx, this);
66 
67             // Check 'try' block.  A variable is DA (DU) before the try
68             // block if it is DA (DU) before the try statement.
69             Vset vs = body.check(env, newctx, vset.copy(), newexp);
70 
71             // A variable is DA before a catch block if it is DA before the
72             // try statement.  A variable is DU before a catch block if it
73             // is DU after the try block and before any 'break', 'continue',
74             // 'throw', or 'return' contained therein. That is, the variable
75             // is DU upon entry to the try-statement and is not assigned to
76             // anywhere within the try block.
77             Vset cvs = Vset.firstDAandSecondDU(vset, vs.copy().join(newctx.vsTryExit));
78 
79             for (int i = 0 ; i < args.length ; i++) {
80                 // A variable is DA (DU) after a try statement if
81                 // it is DA (DU) after every catch block.
82                 vs = vs.join(args[i].check(env, newctx, cvs.copy(), exp));
83             }
84 
85             // Check that catch statements are actually reached
86             for (int i = 1 ; i < args.length ; i++) {
87                 CatchStatement cs = (CatchStatement)args[i];
88                 if (cs.field == null) {
89                     continue;
90                 }
91                 Type type = cs.field.getType();
92                 ClassDefinition def = env.getClassDefinition(type);
93 
94                 for (int j = 0 ; j < i ; j++) {
95                     CatchStatement cs2 = (CatchStatement)args[j];
96                     if (cs2.field == null) {
97                         continue;
98                     }
99                     Type t = cs2.field.getType();
100                     ClassDeclaration c = env.getClassDeclaration(t);
101                     if (def.subClassOf(env, c)) {
102                         env.error(args[i].where, "catch.not.reached");
103                         break;
104                     }
105                 }
106             }
107 
108             ClassDeclaration ignore1 = env.getClassDeclaration(idJavaLangError);
109             ClassDeclaration ignore2 = env.getClassDeclaration(idJavaLangRuntimeException);
110 
111             // Make sure the exception is actually throw in that part of the code
112             for (int i = 0 ; i < args.length ; i++) {
113                 CatchStatement cs = (CatchStatement)args[i];
114                 if (cs.field == null) {
115                     continue;
116                 }
117                 Type type = cs.field.getType();
118                 if (!type.isType(TC_CLASS)) {
119                     // CatchStatement.checkValue() will have already printed
120                     // an error message
121                     continue;
122                 }
123 
124                 ClassDefinition def = env.getClassDefinition(type);
125 
126                 // Anyone can throw these!
127                 if (def.subClassOf(env, ignore1) || def.superClassOf(env, ignore1) ||
128                     def.subClassOf(env, ignore2) || def.superClassOf(env, ignore2)) {
129                     continue;
130                 }
131 
132                 // Make sure the exception is actually throw in that part of the code
133                 boolean ok = false;
134                 for (Enumeration<?> e = newexp.keys() ; e.hasMoreElements() ; ) {
135                     ClassDeclaration c = (ClassDeclaration)e.nextElement();
136                     if (def.superClassOf(env, c) || def.subClassOf(env, c)) {
137                         ok = true;
138                         break;
139                     }
140                 }
141                 if (!ok && arrayCloneWhere != 0
142                     && def.getName().toString().equals("java.lang.CloneNotSupportedException")) {
143                     env.error(arrayCloneWhere, "warn.array.clone.supported", def.getName());
144                 }
145 
146                 if (!ok) {
147                     env.error(cs.where, "catch.not.thrown", def.getName());
148                 }
149             }
150 
151             // Only carry over exceptions that are not caught
152             for (Enumeration<?> e = newexp.keys() ; e.hasMoreElements() ; ) {
153                 ClassDeclaration c = (ClassDeclaration)e.nextElement();
154                 ClassDefinition def = c.getClassDefinition(env);
155                 boolean add = true;
156                 for (int i = 0 ; i < args.length ; i++) {
157                     CatchStatement cs = (CatchStatement)args[i];
158                     if (cs.field == null) {
159                         continue;
160                     }
161                     Type type = cs.field.getType();
162                     if (type.isType(TC_ERROR))
163                         continue;
164                     if (def.subClassOf(env, env.getClassDeclaration(type))) {
165                         add = false;
166                         break;
167                     }
168                 }
169                 if (add) {
170                     exp.put(c, newexp.get(c));
171                 }
172             }
173             // A variable is DA (DU) after a try statement if it is DA (DU)
174             // after the try block and after every catch block. These variables
175             // are represented by 'vs'.  If the try statement is labelled, we
176             // may also exit from it (including from within a catch block) via
177             // a break statement.
178             // If there is a finally block, the Vset returned here is further
179             // adjusted. Note that this 'TryStatement' node will be a child of
180             // a 'FinallyStatement' node in that case.
181             return ctx.removeAdditionalVars(vs.join(newctx.vsBreak));
182         } catch (ClassNotFound e) {
183             env.error(where, "class.not.found", e.name, opNames[op]);
184             return vset;
185         }
186     }
187 
188     /**
189      * Inline
190      */
inline(Environment env, Context ctx)191     public Statement inline(Environment env, Context ctx) {
192         if (body != null) {
193             body = body.inline(env, new Context(ctx, this));
194         }
195         if (body == null) {
196             return null;
197         }
198         for (int i = 0 ; i < args.length ; i++) {
199             if (args[i] != null) {
200                 args[i] = args[i].inline(env, new Context(ctx, this));
201             }
202         }
203         return (args.length == 0) ? eliminate(env, body) : this;
204     }
205 
206     /**
207      * Create a copy of the statement for method inlining
208      */
copyInline(Context ctx, boolean valNeeded)209     public Statement copyInline(Context ctx, boolean valNeeded) {
210         TryStatement s = (TryStatement)clone();
211         if (body != null) {
212             s.body = body.copyInline(ctx, valNeeded);
213         }
214         s.args = new Statement[args.length];
215         for (int i = 0 ; i < args.length ; i++) {
216             if (args[i] != null) {
217                 s.args[i] = args[i].copyInline(ctx, valNeeded);
218             }
219         }
220         return s;
221     }
222 
223     /**
224      * Compute cost of inlining this statement
225      */
costInline(int thresh, Environment env, Context ctx)226     public int costInline(int thresh, Environment env, Context ctx){
227 
228         // Don't inline methods containing try statements.
229         // If the try statement is being inlined in order to
230         // inline a method that returns a value which is
231         // a subexpression of an expression involving the
232         // operand stack, then the early operands may get lost.
233         // This shows up as a verifier error.  For example,
234         // in the following:
235         //
236         //    public static int test() {
237         //       try { return 2; } catch (Exception e)  { return 0; }
238         //    }
239         //
240         //    System.out.println(test());
241         //
242         // an inlined call to test() might look like this:
243         //
244         //     0 getstatic <Field java.io.PrintStream out>
245         //     3 iconst_2
246         //     4 goto 9
247         //     7 pop
248         //     8 iconst_0
249         //     9 invokevirtual <Method void println(int)>
250         //    12 return
251         //  Exception table:
252         //     from   to  target type
253         //       3     7     7   <Class java.lang.Exception>
254         //
255         // This fails to verify because the operand stored
256         // for System.out gets axed at an exception, leading to
257         // an inconsistent stack depth at pc=7.
258         //
259         // Note that although all code must be able to be inlined
260         // to implement initializers, this problem doesn't come up,
261         // as try statements themselves can never be expressions.
262         // It suffices here to make sure they are never inlined as part
263         // of optimization.
264 
265         return thresh;
266     }
267 
268     /**
269      * Code
270      */
code(Environment env, Context ctx, Assembler asm)271     public void code(Environment env, Context ctx, Assembler asm) {
272         CodeContext newctx = new CodeContext(ctx, this);
273 
274         TryData td = new TryData();
275         for (int i = 0 ; i < args.length ; i++) {
276             Type t = ((CatchStatement)args[i]).field.getType();
277             if (t.isType(TC_CLASS)) {
278                 td.add(env.getClassDeclaration(t));
279             } else {
280                 td.add(t);
281             }
282         }
283         asm.add(where, opc_try, td);
284         if (body != null) {
285             body.code(env, newctx, asm);
286         }
287 
288         asm.add(td.getEndLabel());
289         asm.add(where, opc_goto, newctx.breakLabel);
290 
291         for (int i = 0 ; i < args.length ; i++) {
292             CatchData cd = td.getCatch(i);
293             asm.add(cd.getLabel());
294             args[i].code(env, newctx, asm);
295             asm.add(where, opc_goto, newctx.breakLabel);
296         }
297 
298         asm.add(newctx.breakLabel);
299     }
300 
301     /**
302      * Print
303      */
print(PrintStream out, int indent)304     public void print(PrintStream out, int indent) {
305         super.print(out, indent);
306         out.print("try ");
307         if (body != null) {
308             body.print(out, indent);
309         } else {
310             out.print("<empty>");
311         }
312         for (int i = 0 ; i < args.length ; i++) {
313             out.print(" ");
314             args[i].print(out, indent);
315         }
316     }
317 }
318