001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.transformer.bytecode.statement.tag; 020 021import java.util.ArrayList; 022import java.util.Iterator; 023import java.util.List; 024 025import lucee.transformer.bytecode.Body; 026import lucee.transformer.bytecode.BodyBase; 027import lucee.transformer.bytecode.BytecodeContext; 028import lucee.transformer.bytecode.BytecodeException; 029import lucee.transformer.bytecode.Position; 030import lucee.transformer.bytecode.Statement; 031import lucee.transformer.bytecode.expression.ExprString; 032import lucee.transformer.bytecode.expression.Expression; 033import lucee.transformer.bytecode.literal.LitString; 034import lucee.transformer.bytecode.statement.FlowControlFinal; 035import lucee.transformer.bytecode.statement.FlowControlFinalImpl; 036import lucee.transformer.bytecode.statement.FlowControlRetry; 037import lucee.transformer.bytecode.statement.TryCatchFinally; 038import lucee.transformer.bytecode.util.ExpressionUtil; 039import lucee.transformer.bytecode.util.Types; 040import lucee.transformer.bytecode.visitor.OnFinally; 041import lucee.transformer.bytecode.visitor.TryCatchFinallyVisitor; 042 043import org.objectweb.asm.Label; 044import org.objectweb.asm.Opcodes; 045import org.objectweb.asm.Type; 046import org.objectweb.asm.commons.GeneratorAdapter; 047import org.objectweb.asm.commons.Method; 048 049public final class TagTry extends TagBase implements FlowControlRetry { 050 051 private static final ExprString ANY=LitString.toExprString("any"); 052 053 private static final Method GET_VARIABLE = new Method( 054 "getVariable", 055 Types.OBJECT, 056 new Type[]{Types.STRING}); 057 058 private static final Method TO_PAGE_EXCEPTION = new Method( 059 "toPageException", 060 Types.PAGE_EXCEPTION, 061 new Type[]{Types.THROWABLE}); 062 063 064 public static final Method SET_CATCH_PE = new Method( 065 "setCatch", 066 Types.VOID, 067 new Type[]{Types.PAGE_EXCEPTION}); 068 069 public static final Method SET_CATCH3 = new Method( 070 "setCatch", 071 Types.VOID, 072 new Type[]{Types.PAGE_EXCEPTION,Types.BOOLEAN_VALUE,Types.BOOLEAN_VALUE}); 073 074 public static final Method GET_CATCH = new Method( 075 "getCatch", 076 Types.PAGE_EXCEPTION, 077 new Type[]{}); 078 079 // public boolean typeEqual(String type); 080 private static final Method TYPE_EQUAL = new Method( 081 "typeEqual", 082 Types.BOOLEAN_VALUE, 083 new Type[]{Types.STRING}); 084 085 private FlowControlFinal fcf; 086 087 private boolean checked; 088 private Label begin = new Label(); 089 090 091 public TagTry(Position start,Position end) { 092 super(start,end); 093 } 094 095 /** 096 * 097 * @see lucee.transformer.bytecode.statement.tag.TagBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter) 098 */ 099 public void _writeOut(BytecodeContext bc) throws BytecodeException { 100 GeneratorAdapter adapter = bc.getAdapter(); 101 adapter.visitLabel(begin); 102 Body tryBody=new BodyBase(); 103 List<Tag> catches=new ArrayList<Tag>(); 104 Tag tmpFinal=null; 105 106 tryBody.setParent(getBody().getParent()); 107 108 List<Statement> statements = getBody().getStatements(); 109 Statement stat; 110 Tag tag; 111 { 112 Iterator<Statement> it = statements.iterator(); 113 while(it.hasNext()) { 114 stat= it.next(); 115 if(stat instanceof Tag) { 116 tag=(Tag) stat; 117 if(tag.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Catch")) { 118 catches.add(tag); 119 continue; 120 } 121 else if(tag.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Finally")) { 122 tmpFinal=tag; 123 continue; 124 } 125 } 126 tryBody.addStatement(stat); 127 }; 128 } 129 final Tag _finally=tmpFinal; 130 131 // has no try body, if there is no try body, no catches are executed, only finally 132 if(!tryBody.hasStatements()) { 133 134 if(_finally!=null && _finally.getBody()!=null){ 135 BodyBase.writeOut(bc, _finally.getBody()); 136 //ExpressionUtil.writeOut(_finally.getBody(), bc); 137 } 138 return; 139 } 140 TryCatchFinallyVisitor tcfv=new TryCatchFinallyVisitor(new OnFinally() { 141 142 public void _writeOut(BytecodeContext bc) throws BytecodeException { 143 if(_finally!=null) { 144 145 ExpressionUtil.visitLine(bc, _finally.getStart()); 146 BodyBase.writeOut(bc, _finally.getBody()); 147 //ExpressionUtil.writeOut(_finally.getBody(), bc); 148 } 149 } 150 },getFlowControlFinal()); 151 152 153 // Try 154 tcfv.visitTryBegin(bc); 155 BodyBase.writeOut(bc, tryBody); 156 //ExpressionUtil.writeOut(tryBody, bc); 157 int e=tcfv.visitTryEndCatchBeging(bc); 158 // if(e instanceof lucee.runtime.exp.Abort) throw e; 159 Label abortEnd=new Label(); 160 adapter.loadLocal(e); 161 // Abort.isAbort(t); 162 adapter.invokeStatic(Types.ABORT, TryCatchFinally.IS_ABORT); 163 //adapter.instanceOf(Types.ABORT); 164 165 166 167 adapter.ifZCmp(Opcodes.IFEQ, abortEnd); 168 adapter.loadLocal(e); 169 adapter.throwException(); 170 adapter.visitLabel(abortEnd); 171 172 173 // PageExceptionImpl old=pc.getCatch(); 174 int old=adapter.newLocal(Types.PAGE_EXCEPTION); 175 adapter.loadArg(0); 176 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_CATCH); 177 adapter.storeLocal(old); 178 179 // PageException pe=Caster.toPageEception(e); 180 int pe=adapter.newLocal(Types.PAGE_EXCEPTION); 181 adapter.loadLocal(e); 182 adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION); 183 adapter.storeLocal(pe); 184 185 Iterator<Tag> it = catches.iterator(); 186 Attribute attrType; 187 Expression type; 188 Label endAllIfs=new Label(); 189 Tag tagElse=null; 190 while(it.hasNext()) { 191 tag=it.next(); 192 Label endIf=new Label(); 193 attrType = tag.getAttribute("type"); 194 type=ANY; 195 if(attrType!=null)type=attrType.getValue(); 196 197 if(type instanceof LitString && ((LitString)type).getString().equalsIgnoreCase("any")){ 198 tagElse=tag; 199 continue; 200 } 201 202 ExpressionUtil.visitLine(bc, tag.getStart()); 203 204 // if(pe.typeEqual(@type) 205 adapter.loadLocal(pe); 206 type.writeOut(bc, Expression.MODE_REF); 207 adapter.invokeVirtual(Types.PAGE_EXCEPTION, TYPE_EQUAL); 208 209 adapter.ifZCmp(Opcodes.IFEQ, endIf); 210 catchBody(bc,adapter,tag,pe,true,true); 211 212 adapter.visitJumpInsn(Opcodes.GOTO, endAllIfs); 213 214 adapter.visitLabel(endIf); 215 216 217 } 218 // else 219 if(tagElse!=null){ 220 catchBody(bc, adapter, tagElse, pe, true,true); 221 } 222 else{ 223 // pc.setCatch(pe,true); 224 adapter.loadArg(0); 225 adapter.loadLocal(pe); 226 adapter.push(false); 227 adapter.push(true); 228 adapter.invokeVirtual(Types.PAGE_CONTEXT, SET_CATCH3); 229 230 //throw pe; 231 adapter.loadLocal(pe); 232 adapter.throwException(); 233 } 234 adapter.visitLabel(endAllIfs); 235 236 237 // PageExceptionImpl old=pc.getCatch(); 238 adapter.loadArg(0); 239 adapter.loadLocal(old); 240 adapter.invokeVirtual(Types.PAGE_CONTEXT, SET_CATCH_PE); 241 242 tcfv.visitCatchEnd(bc); 243 } 244 245 246 private static void catchBody(BytecodeContext bc, GeneratorAdapter adapter,Tag tag, int pe,boolean caugth, boolean store) throws BytecodeException { 247 // pc.setCatch(pe,true); 248 adapter.loadArg(0); 249 adapter.loadLocal(pe); 250 adapter.push(caugth); 251 adapter.push(store); 252 adapter.invokeVirtual(Types.PAGE_CONTEXT, SET_CATCH3); 253 BodyBase.writeOut(bc, tag.getBody()); 254 //ExpressionUtil.writeOut(tag.getBody(), bc); 255 256 } 257 258 private boolean hasFinally(){ 259 List<Statement> statements = getBody().getStatements(); 260 Statement stat; 261 Tag tag; 262 Iterator<Statement> it = statements.iterator(); 263 while(it.hasNext()) { 264 stat= it.next(); 265 if(stat instanceof Tag) { 266 tag=(Tag) stat; 267 if(tag.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Finally")) { 268 return true; 269 } 270 } 271 } 272 return false; 273 } 274 275 276 @Override 277 public FlowControlFinal getFlowControlFinal() { 278 if(!checked) { 279 checked=true; 280 if(!hasFinally()) return null; 281 fcf=new FlowControlFinalImpl(); 282 } 283 284 return fcf; 285 } 286 287 @Override 288 public Label getRetryLabel() { 289 return begin; 290 } 291 292 @Override 293 public String getLabel() { 294 return null; 295 } 296 297 298}