001 package railo.transformer.bytecode.statement; 002 003 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 import java.util.List; 007 008 import org.objectweb.asm.Label; 009 import org.objectweb.asm.Opcodes; 010 import org.objectweb.asm.Type; 011 import org.objectweb.asm.commons.GeneratorAdapter; 012 import org.objectweb.asm.commons.Method; 013 014 import railo.runtime.type.scope.Scope; 015 import railo.transformer.bytecode.Body; 016 import railo.transformer.bytecode.BytecodeContext; 017 import railo.transformer.bytecode.BytecodeException; 018 import railo.transformer.bytecode.Position; 019 import railo.transformer.bytecode.expression.ExprString; 020 import railo.transformer.bytecode.expression.Expression; 021 import railo.transformer.bytecode.expression.var.DataMember; 022 import railo.transformer.bytecode.expression.var.Variable; 023 import railo.transformer.bytecode.expression.var.VariableRef; 024 import railo.transformer.bytecode.expression.var.VariableString; 025 import railo.transformer.bytecode.literal.LitBoolean; 026 import railo.transformer.bytecode.literal.LitString; 027 import railo.transformer.bytecode.statement.tag.TagTry; 028 import railo.transformer.bytecode.util.ExpressionUtil; 029 import railo.transformer.bytecode.util.Types; 030 import railo.transformer.bytecode.visitor.OnFinally; 031 import railo.transformer.bytecode.visitor.TryCatchFinallyVisitor; 032 033 /** 034 * produce try-catch-finally 035 */ 036 public final class TryCatchFinally extends StatementBase implements Opcodes,HasBodies,FlowControlRetry { 037 038 //private static LitString ANY=LitString.toExprString("any", -1); 039 040 private static final Method TO_PAGE_EXCEPTION = new Method( 041 "toPageException", 042 Types.PAGE_EXCEPTION, 043 new Type[]{Types.THROWABLE}); 044 045 046 047 // public boolean typeEqual(String type); 048 private static final Method TYPE_EQUAL = new Method( 049 "typeEqual", 050 Types.BOOLEAN_VALUE, 051 new Type[]{Types.STRING}); 052 053 054 // Struct getCatchBlock(PageContext pc); 055 private static final Method GET_CATCH_BLOCK = new Method( 056 "getCatchBlock", 057 Types.STRUCT, 058 new Type[]{Types.PAGE_CONTEXT}); 059 060 061 // void isAbort(e) 062 public static final Method IS_ABORT = new Method( 063 "isAbort", 064 Types.BOOLEAN_VALUE, 065 new Type[]{Types.THROWABLE}); 066 067 068 069 private final static Method SET = new Method("set",Types.OBJECT,new Type[]{Types.PAGE_CONTEXT,Types.OBJECT}); 070 071 private static final Method REMOVE_EL = new Method("removeEL",Types.OBJECT,new Type[]{Types.PAGE_CONTEXT}); 072 073 074 075 076 private Body tryBody; 077 private Body finallyBody; 078 private List<Catch> catches=new ArrayList<Catch>(); 079 private Position finallyLine; 080 081 082 private Label begin = new Label(); 083 084 private FlowControlFinal fcf; 085 086 087 /** 088 * Constructor of the class 089 * @param body 090 * @param line 091 */ 092 public TryCatchFinally(Body body,Position start, Position end) { 093 super(start,end); 094 this.tryBody=body; 095 body.setParent(this); 096 } 097 098 /** 099 * sets finally body 100 * @param body 101 */ 102 public void setFinally(Body body, Position finallyLine) { 103 body.setParent(this); 104 this.finallyBody=body; 105 this.finallyLine=finallyLine; 106 } 107 108 /** 109 * data for a single catch block 110 */ 111 private class Catch { 112 113 private ExprString type; 114 private Body body; 115 private VariableRef name; 116 private Position line; 117 118 public Catch(ExprString type, VariableRef name, Body body, Position line) { 119 this.type=type; 120 this.name=name; 121 this.body=body; 122 this.line=line; 123 } 124 125 } 126 127 128 129 /** 130 * 131 * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter) 132 */ 133 public void _writeOut(BytecodeContext bc) throws BytecodeException { 134 GeneratorAdapter adapter = bc.getAdapter(); 135 136 adapter.visitLabel(begin); 137 138 // Reference ref=null; 139 final int lRef=adapter.newLocal(Types.REFERENCE); 140 adapter.visitInsn(Opcodes.ACONST_NULL); 141 adapter.storeLocal(lRef); 142 143 // has no try body, if there is no try body, no catches are executed, only finally 144 if(!tryBody.hasStatements()) { 145 if(finallyBody!=null)finallyBody.writeOut(bc); 146 return; 147 } 148 149 150 TryCatchFinallyVisitor tcfv=new TryCatchFinallyVisitor(new OnFinally() { 151 152 public void writeOut(BytecodeContext bc) throws BytecodeException { 153 _writeOutFinally(bc,lRef); 154 } 155 },getFlowControlFinal()); 156 157 // try 158 tcfv.visitTryBegin(bc); 159 tryBody.writeOut(bc); 160 int lThrow = tcfv.visitTryEndCatchBeging(bc); 161 _writeOutCatch(bc, lRef, lThrow); 162 tcfv.visitCatchEnd(bc); 163 164 } 165 166 167 168 169 170 171 172 173 private void _writeOutFinally(BytecodeContext bc, int lRef) throws BytecodeException { 174 // ref.remove(pc); 175 //Reference r=null; 176 GeneratorAdapter adapter = bc.getAdapter(); 177 178 //if(fcf!=null && fcf.getAfterFinalGOTOLabel()!=null)ASMUtil.visitLabel(adapter,fcf.getFinalEntryLabel()); 179 ExpressionUtil.visitLine(bc, finallyLine); 180 181 182 183 //if (reference != null) 184 // reference.removeEL(pagecontext); 185 Label removeEnd=new Label(); 186 adapter.loadLocal(lRef); 187 adapter.ifNull(removeEnd); 188 adapter.loadLocal(lRef); 189 adapter.loadArg(0); 190 adapter.invokeInterface(Types.REFERENCE, REMOVE_EL); 191 adapter.pop(); 192 adapter.visitLabel(removeEnd); 193 194 if(finallyBody!=null)finallyBody.writeOut(bc); // finally 195 /*if(fcf!=null){ 196 Label l = fcf.getAfterFinalGOTOLabel(); 197 if(l!=null)adapter.visitJumpInsn(Opcodes.GOTO, l); 198 }*/ 199 } 200 201 private void _writeOutCatch(BytecodeContext bc, int lRef,int lThrow) throws BytecodeException { 202 GeneratorAdapter adapter = bc.getAdapter(); 203 int pe=adapter.newLocal(Types.PAGE_EXCEPTION); 204 205 206 // instance of Abort 207 Label abortEnd=new Label(); 208 adapter.loadLocal(lThrow); 209 adapter.invokeStatic(Types.ABORT, TryCatchFinally.IS_ABORT); 210 //adapter.instanceOf(Types.ABORT); 211 adapter.ifZCmp(Opcodes.IFEQ, abortEnd); 212 adapter.loadLocal(lThrow); 213 adapter.throwException(); 214 adapter.visitLabel(abortEnd); 215 216 217 // PageExceptionImpl old=pc.getCatch(); 218 int old=adapter.newLocal(Types.PAGE_EXCEPTION); 219 adapter.loadArg(0); 220 adapter.invokeVirtual(Types.PAGE_CONTEXT, TagTry.GET_CATCH); 221 adapter.storeLocal(old); 222 223 224 // cast to PageException Caster.toPagException(t); 225 adapter.loadLocal(lThrow); 226 adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION); 227 228 // PageException pe=... 229 adapter.storeLocal(pe); 230 231 // catch loop 232 Label endAllIf = new Label(); 233 Iterator<Catch> it = catches.iterator(); 234 Catch ctElse=null; 235 while(it.hasNext()) { 236 Catch ct=it.next(); 237 // store any for else 238 if(ct.type!=null && ct.type instanceof LitString && ((LitString)ct.type).getString().equalsIgnoreCase("any")){ 239 ctElse=ct; 240 continue; 241 } 242 243 ExpressionUtil.visitLine(bc, ct.line); 244 245 // pe.typeEqual(type) 246 if(ct.type==null){ 247 LitBoolean.TRUE.writeOut(bc, Expression.MODE_VALUE); 248 } 249 else { 250 adapter.loadLocal(pe); 251 ct.type.writeOut(bc, Expression.MODE_REF); 252 adapter.invokeVirtual(Types.PAGE_EXCEPTION, TYPE_EQUAL); 253 } 254 255 256 257 258 Label endIf = new Label(); 259 adapter.ifZCmp(Opcodes.IFEQ, endIf); 260 261 catchBody(bc,adapter,ct,pe,lRef,true); 262 263 adapter.visitJumpInsn(Opcodes.GOTO, endAllIf); 264 adapter.visitLabel(endIf); 265 266 267 268 } 269 270 if(ctElse!=null){ 271 catchBody(bc,adapter,ctElse,pe,lRef,true); 272 } 273 else{ 274 // pc.setCatch(pe,true); 275 adapter.loadArg(0); 276 adapter.loadLocal(pe); 277 adapter.push(false); 278 adapter.push(false); 279 adapter.invokeVirtual(Types.PAGE_CONTEXT, TagTry.SET_CATCH3); 280 281 282 adapter.loadLocal(pe); 283 adapter.throwException(); 284 } 285 adapter.visitLabel(endAllIf); 286 287 // PageExceptionImpl old=pc.setCatch(old); 288 adapter.loadArg(0); 289 adapter.loadLocal(old); 290 adapter.invokeVirtual(Types.PAGE_CONTEXT, TagTry.SET_CATCH_PE); 291 292 } 293 294 private static void catchBody(BytecodeContext bc, GeneratorAdapter adapter, Catch ct, int pe, int lRef,boolean caugth) throws BytecodeException { 295 // pc.setCatch(pe,true); 296 adapter.loadArg(0); 297 adapter.loadLocal(pe); 298 adapter.push(caugth); 299 adapter.push(false); 300 adapter.invokeVirtual(Types.PAGE_CONTEXT, TagTry.SET_CATCH3); 301 302 303 // ref= 304 ct.name.writeOut(bc, Expression.MODE_REF); 305 adapter.storeLocal(lRef); 306 307 adapter.loadLocal(lRef); 308 adapter.loadArg(0); 309 adapter.loadLocal(pe);// (...,pe.getCatchBlock(pc)) 310 adapter.loadArg(0); 311 adapter.invokeVirtual(Types.PAGE_EXCEPTION, GET_CATCH_BLOCK); 312 adapter.invokeInterface(Types.REFERENCE, SET); 313 adapter.pop(); 314 315 ct.body.writeOut(bc); 316 } 317 318 /** 319 * @param type 320 * @param name 321 * @param body 322 * @param line 323 */ 324 public void addCatch(ExprString type, VariableRef name, Body body, Position line) { 325 body.setParent(this); 326 catches.add(new Catch(type,name,body,line)); 327 } 328 329 /** 330 * @param type 331 * @param name 332 * @param b 333 * @param line 334 * @throws BytecodeException 335 */ 336 public void addCatch(Expression type, Expression name, Body b, Position line) throws BytecodeException { 337 338 // type 339 if(type==null || type instanceof ExprString) ; 340 else if(type instanceof Variable) { 341 type=VariableString.toExprString(type); 342 } 343 else throw new BytecodeException("type from catch statement is invalid",type.getStart()); 344 345 // name 346 if(name instanceof LitString){ 347 Variable v = new Variable(Scope.SCOPE_UNDEFINED,name.getStart(),name.getEnd()); 348 v.addMember(new DataMember(name)); 349 name=new VariableRef(v); 350 } 351 else if(name instanceof Variable) name=new VariableRef((Variable) name); 352 else throw new BytecodeException("name from catch statement is invalid",name.getStart()); 353 354 addCatch((ExprString)type, (VariableRef)name, b, line); 355 } 356 357 358 /** 359 * @see railo.transformer.bytecode.statement.HasBodies#getBodies() 360 */ 361 public Body[] getBodies() { 362 363 int len=catches.size(),count=0; 364 if(tryBody!=null)len++; 365 if(finallyBody!=null)len++; 366 Body[] bodies=new Body[len]; 367 Catch c; 368 Iterator<Catch> it = catches.iterator(); 369 while(it.hasNext()) { 370 c=it.next(); 371 bodies[count++]=c.body; 372 } 373 if(tryBody!=null)bodies[count++]=tryBody; 374 if(finallyBody!=null)bodies[count++]=finallyBody; 375 376 return bodies; 377 } 378 379 @Override 380 public FlowControlFinal getFlowControlFinal() { 381 if(fcf==null) fcf=new FlowControlFinalImpl(); 382 return fcf; 383 } 384 385 @Override 386 public Label getRetryLabel() { 387 return begin; 388 } 389 390 @Override 391 public String getLabel() { 392 return null; 393 } 394 }