package railo.transformer.bytecode.statement.tag; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import railo.transformer.bytecode.Body; import railo.transformer.bytecode.BodyBase; import railo.transformer.bytecode.BytecodeContext; import railo.transformer.bytecode.BytecodeException; import railo.transformer.bytecode.Position; import railo.transformer.bytecode.Statement; import railo.transformer.bytecode.expression.ExprString; import railo.transformer.bytecode.expression.Expression; import railo.transformer.bytecode.literal.LitString; import railo.transformer.bytecode.statement.FlowControlFinal; import railo.transformer.bytecode.statement.FlowControlFinalImpl; import railo.transformer.bytecode.statement.FlowControlRetry; import railo.transformer.bytecode.statement.TryCatchFinally; import railo.transformer.bytecode.util.ExpressionUtil; import railo.transformer.bytecode.util.Types; import railo.transformer.bytecode.visitor.OnFinally; import railo.transformer.bytecode.visitor.TryCatchFinallyVisitor; public final class TagTry extends TagBase implements FlowControlRetry { private static final ExprString ANY=LitString.toExprString("any"); private static final Method GET_VARIABLE = new Method( "getVariable", Types.OBJECT, new Type[]{Types.STRING}); private static final Method TO_PAGE_EXCEPTION = new Method( "toPageException", Types.PAGE_EXCEPTION, new Type[]{Types.THROWABLE}); public static final Method SET_CATCH_PE = new Method( "setCatch", Types.VOID, new Type[]{Types.PAGE_EXCEPTION}); public static final Method SET_CATCH3 = new Method( "setCatch", Types.VOID, new Type[]{Types.PAGE_EXCEPTION,Types.BOOLEAN_VALUE,Types.BOOLEAN_VALUE}); public static final Method GET_CATCH = new Method( "getCatch", Types.PAGE_EXCEPTION, new Type[]{}); // public boolean typeEqual(String type); private static final Method TYPE_EQUAL = new Method( "typeEqual", Types.BOOLEAN_VALUE, new Type[]{Types.STRING}); private FlowControlFinal fcf; private boolean checked; private Label begin = new Label(); public TagTry(Position start,Position end) { super(start,end); } /** * * @see railo.transformer.bytecode.statement.tag.TagBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter) */ public void _writeOut(BytecodeContext bc) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); adapter.visitLabel(begin); Body tryBody=new BodyBase(); List<Tag> catches=new ArrayList<Tag>(); Tag tmpFinal=null; tryBody.setParent(getBody().getParent()); List<Statement> statements = getBody().getStatements(); Statement stat; Tag tag; { Iterator<Statement> it = statements.iterator(); while(it.hasNext()) { stat= it.next(); if(stat instanceof Tag) { tag=(Tag) stat; if(tag.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Catch")) { catches.add(tag); continue; } else if(tag.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Finally")) { tmpFinal=tag; continue; } } tryBody.addStatement(stat); }; } final Tag _finally=tmpFinal; // has no try body, if there is no try body, no catches are executed, only finally if(!tryBody.hasStatements()) { if(_finally!=null && _finally.getBody()!=null)_finally.getBody().writeOut(bc); return; } TryCatchFinallyVisitor tcfv=new TryCatchFinallyVisitor(new OnFinally() { public void writeOut(BytecodeContext bc) throws BytecodeException { /*GeneratorAdapter ga = bc.getAdapter(); if(fcf!=null && fcf.getAfterFinalGOTOLabel()!=null) ASMUtil.visitLabel(ga,fcf.getFinalEntryLabel()); */ if(_finally!=null) { ExpressionUtil.visitLine(bc, _finally.getStart()); _finally.getBody().writeOut(bc); } /*if(fcf!=null){ Label l=fcf.getAfterFinalGOTOLabel(); if(l!=null)ga.visitJumpInsn(Opcodes.GOTO, l); }*/ } },getFlowControlFinal()); // Try tcfv.visitTryBegin(bc); tryBody.writeOut(bc); int e=tcfv.visitTryEndCatchBeging(bc); // if(e instanceof railo.runtime.exp.Abort) throw e; Label abortEnd=new Label(); adapter.loadLocal(e); // Abort.isAbort(t); adapter.invokeStatic(Types.ABORT, TryCatchFinally.IS_ABORT); //adapter.instanceOf(Types.ABORT); adapter.ifZCmp(Opcodes.IFEQ, abortEnd); adapter.loadLocal(e); adapter.throwException(); adapter.visitLabel(abortEnd); // PageExceptionImpl old=pc.getCatch(); int old=adapter.newLocal(Types.PAGE_EXCEPTION); adapter.loadArg(0); adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_CATCH); adapter.storeLocal(old); // PageException pe=Caster.toPageEception(e); int pe=adapter.newLocal(Types.PAGE_EXCEPTION); adapter.loadLocal(e); adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION); adapter.storeLocal(pe); Iterator<Tag> it = catches.iterator(); Attribute attrType; Expression type; Label endAllIfs=new Label(); Tag tagElse=null; while(it.hasNext()) { tag=it.next(); Label endIf=new Label(); attrType = tag.getAttribute("type"); type=ANY; if(attrType!=null)type=attrType.getValue(); if(type instanceof LitString && ((LitString)type).getString().equalsIgnoreCase("any")){ tagElse=tag; continue; } ExpressionUtil.visitLine(bc, tag.getStart()); // if(pe.typeEqual(@type) adapter.loadLocal(pe); type.writeOut(bc, Expression.MODE_REF); adapter.invokeVirtual(Types.PAGE_EXCEPTION, TYPE_EQUAL); adapter.ifZCmp(Opcodes.IFEQ, endIf); catchBody(bc,adapter,tag,pe,true,true); adapter.visitJumpInsn(Opcodes.GOTO, endAllIfs); adapter.visitLabel(endIf); } // else if(tagElse!=null){ catchBody(bc, adapter, tagElse, pe, true,true); } else{ // pc.setCatch(pe,true); adapter.loadArg(0); adapter.loadLocal(pe); adapter.push(false); adapter.push(true); adapter.invokeVirtual(Types.PAGE_CONTEXT, SET_CATCH3); //throw pe; adapter.loadLocal(pe); adapter.throwException(); } adapter.visitLabel(endAllIfs); // PageExceptionImpl old=pc.getCatch(); adapter.loadArg(0); adapter.loadLocal(old); adapter.invokeVirtual(Types.PAGE_CONTEXT, SET_CATCH_PE); tcfv.visitCatchEnd(bc); } private static void catchBody(BytecodeContext bc, GeneratorAdapter adapter,Tag tag, int pe,boolean caugth, boolean store) throws BytecodeException { // pc.setCatch(pe,true); adapter.loadArg(0); adapter.loadLocal(pe); adapter.push(caugth); adapter.push(store); adapter.invokeVirtual(Types.PAGE_CONTEXT, SET_CATCH3); tag.getBody().writeOut(bc); } private boolean hasFinally(){ List<Statement> statements = getBody().getStatements(); Statement stat; Tag tag; Iterator<Statement> it = statements.iterator(); while(it.hasNext()) { stat= it.next(); if(stat instanceof Tag) { tag=(Tag) stat; if(tag.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Finally")) { return true; } } } return false; } @Override public FlowControlFinal getFlowControlFinal() { if(!checked) { checked=true; if(!hasFinally()) return null; fcf=new FlowControlFinalImpl(); } return fcf; } @Override public Label getRetryLabel() { return begin; } @Override public String getLabel() { return null; } }