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