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