001    package railo.transformer.bytecode.util;
002    
003    import java.util.HashMap;
004    import java.util.Map;
005    
006    import org.objectweb.asm.Opcodes;
007    import org.objectweb.asm.Type;
008    import org.objectweb.asm.commons.GeneratorAdapter;
009    import org.objectweb.asm.commons.Method;
010    
011    import railo.commons.lang.CFTypes;
012    import railo.commons.lang.StringUtil;
013    import railo.runtime.op.Caster;
014    import railo.transformer.bytecode.BytecodeContext;
015    import railo.transformer.bytecode.BytecodeException;
016    import railo.transformer.bytecode.Statement;
017    import railo.transformer.bytecode.expression.ExprString;
018    import railo.transformer.bytecode.expression.Expression;
019    import railo.transformer.bytecode.literal.LitString;
020    import railo.transformer.bytecode.statement.StatementBase;
021    import railo.transformer.bytecode.statement.tag.Tag;
022    
023    public final class ExpressionUtil {
024    
025            /*public static final Method END_LINE = new Method(
026                            "exeLogEndline",
027                            Types.VOID,
028                            new Type[]{Types.INT_VALUE});*/
029            
030            public static final Method START = new Method(
031                            "exeLogStart",
032                            Types.VOID,
033                            new Type[]{Types.INT_VALUE,Types.STRING});
034            public static final Method END = new Method(
035                            "exeLogEnd",
036                            Types.VOID,
037                            new Type[]{Types.INT_VALUE,Types.STRING});
038            
039    
040            private static Map<String,String> last=new HashMap<String,String>();
041    
042            public static void writeOutExpressionArray(BytecodeContext bc, Type arrayType, Expression[] array) throws BytecodeException {
043            GeneratorAdapter adapter = bc.getAdapter();
044            adapter.push(array.length);
045            adapter.newArray(arrayType);
046            for (int i = 0; i < array.length; i++) {
047                adapter.dup();
048                adapter.push(i);
049                array[i].writeOut(bc, Expression.MODE_REF);
050                adapter.visitInsn(Opcodes.AASTORE);
051            }
052        }
053    
054        /**
055         * visit line number
056         * @param adapter
057         * @param line
058         * @param silent id silent this is ignored for log
059         */
060        public static synchronized void visitLine(BytecodeContext bc, int line) {
061            if(line>0){
062                    if(!(""+line).equals(last.get(bc.getClassName()+":"+bc.getId()))){
063                            //writeLog(bc,line);
064                            bc.visitLineNumber(line);
065                            last.put(bc.getClassName()+":"+bc.getId(),""+line);
066                            last.put(bc.getClassName(),""+line);
067                    }
068            }
069       }
070    
071            public static synchronized void lastLine(BytecodeContext bc) {
072            int line = Caster.toIntValue(last.get(bc.getClassName()),-1);
073            visitLine(bc, line);
074        }
075    
076            /**
077             * write out expression without LNT
078             * @param value
079             * @param bc
080             * @param mode
081             * @throws BytecodeException
082             */
083            public static void writeOutSilent(Expression value, BytecodeContext bc, int mode) throws BytecodeException {
084                    int line = value.getLine();
085                    value.setLine(-1);
086                    value.writeOut(bc, mode);
087                    value.setLine(line);
088            }
089            public static void writeOut(Expression value, BytecodeContext bc, int mode) throws BytecodeException {
090                    value.writeOut(bc, mode);
091            }
092    
093            public static short toShortType(ExprString expr, short defaultValue) {
094                    if(expr instanceof LitString){
095                            return CFTypes.toShort(((LitString)expr).getString(),defaultValue);
096                    }
097                    return defaultValue;
098            }
099    
100            public static void callStartLog(BytecodeContext bc, Statement s, String id) {
101                    call_Log(bc, START, getStartLine(s),id);
102            }
103            public static void callEndLog(BytecodeContext bc, Statement s, String id) {
104                    call_Log(bc, END, getEndLine(s),id);
105            }
106    
107            private static void call_Log(BytecodeContext bc, Method method, int line, String id) {
108            if(!bc.writeLog() || line<0 || (StringUtil.indexOfIgnoreCase(bc.getMethod().getName(),"call")==-1))return;
109            try{
110                    GeneratorAdapter adapter = bc.getAdapter();
111                    adapter.loadArg(0);
112                    adapter.checkCast(Types.PAGE_CONTEXT_IMPL);
113                    adapter.push(line);
114                    adapter.push(id);
115                        adapter.invokeVirtual(Types.PAGE_CONTEXT_IMPL, method);
116                    }
117                    catch(Throwable t) {
118                            t.printStackTrace();
119                    }               
120            }
121        
122        public static int getStartLine(Statement s){
123            if(s instanceof StatementBase)return ((StatementBase)s).getStartLine();
124            if(s instanceof Tag)return ((Tag)s).getStartLine();
125            return s.getLine();
126        }
127        
128        public static int getEndLine(Statement s){
129            if(s instanceof StatementBase)return ((StatementBase)s).getEndLine();
130            if(s instanceof Tag)return ((Tag)s).getEndLine();
131            return s.getLine();
132        }
133    
134            public static boolean doLog(BytecodeContext bc) {
135                    return bc.writeLog() && StringUtil.indexOfIgnoreCase(bc.getMethod().getName(),"call")!=-1;
136            }
137    }