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