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.util; 020 021import java.util.HashMap; 022import java.util.Map; 023 024import lucee.commons.lang.CFTypes; 025import lucee.commons.lang.ExceptionUtil; 026import lucee.commons.lang.StringUtil; 027import lucee.runtime.op.Caster; 028import lucee.transformer.bytecode.BodyBase; 029import lucee.transformer.bytecode.BytecodeContext; 030import lucee.transformer.bytecode.BytecodeException; 031import lucee.transformer.bytecode.Position; 032import lucee.transformer.bytecode.Statement; 033import lucee.transformer.bytecode.expression.ExprString; 034import lucee.transformer.bytecode.expression.Expression; 035import lucee.transformer.bytecode.literal.LitString; 036import lucee.transformer.bytecode.visitor.OnFinally; 037import lucee.transformer.bytecode.visitor.TryFinallyVisitor; 038 039import org.objectweb.asm.Opcodes; 040import org.objectweb.asm.Type; 041import org.objectweb.asm.commons.GeneratorAdapter; 042import org.objectweb.asm.commons.Method; 043 044public final class ExpressionUtil { 045 046 public static final Method START = new Method( 047 "exeLogStart", 048 Types.VOID, 049 new Type[]{Types.INT_VALUE,Types.STRING}); 050 public static final Method END = new Method( 051 "exeLogEnd", 052 Types.VOID, 053 new Type[]{Types.INT_VALUE,Types.STRING}); 054 055 public static final Method CURRENT_LINE = new Method( 056 "currentLine", 057 Types.VOID, 058 new Type[]{Types.INT_VALUE}); 059 060 061 private static Map<String,String> last=new HashMap<String,String>(); 062 063 public static void writeOutExpressionArray(BytecodeContext bc, Type arrayType, Expression[] array) throws BytecodeException { 064 GeneratorAdapter adapter = bc.getAdapter(); 065 adapter.push(array.length); 066 adapter.newArray(arrayType); 067 for (int i = 0; i < array.length; i++) { 068 adapter.dup(); 069 adapter.push(i); 070 array[i].writeOut(bc, Expression.MODE_REF); 071 adapter.visitInsn(Opcodes.AASTORE); 072 } 073 } 074 075 /** 076 * visit line number 077 * @param adapter 078 * @param line 079 * @param silent id silent this is ignored for log 080 */ 081 public static synchronized void visitLine(BytecodeContext bc, Position pos) { 082 if(pos!=null){ 083 visitLine(bc, pos.line); 084 } 085 } 086 private static synchronized void visitLine(BytecodeContext bc, int line) { 087 if(line>0){ 088 089 /*Type[] methodTypes = bc.getMethod().getArgumentTypes(); 090 if(methodTypes!=null && methodTypes.length>0 && methodTypes[0].equals(Types.PAGE_CONTEXT)) { 091 GeneratorAdapter adapter = bc.getAdapter(); 092 adapter.loadArg(0); 093 adapter.checkCast(Types.PAGE_CONTEXT_IMPL); 094 adapter.push(line); 095 adapter.invokeVirtual(Types.PAGE_CONTEXT_IMPL,CURRENT_LINE ); 096 }*/ 097 098 if(!(""+line).equals(last.get(bc.getClassName()+":"+bc.getId()))){ 099 100 101 102 bc.visitLineNumber(line); 103 last.put(bc.getClassName()+":"+bc.getId(),""+line); 104 last.put(bc.getClassName(),""+line); 105 } 106 } 107 } 108 109 public static synchronized void lastLine(BytecodeContext bc) { 110 int line = Caster.toIntValue(last.get(bc.getClassName()),-1); 111 visitLine(bc, line); 112 } 113 114 /** 115 * write out expression without LNT 116 * @param value 117 * @param bc 118 * @param mode 119 * @throws BytecodeException 120 */ 121 public static void writeOutSilent(Expression value, BytecodeContext bc, int mode) throws BytecodeException { 122 Position start = value.getStart(); 123 Position end = value.getEnd(); 124 value.setStart(null); 125 value.setEnd(null); 126 value.writeOut(bc, mode); 127 value.setStart(start); 128 value.setEnd(end); 129 } 130 public static void writeOut(Expression value, BytecodeContext bc, int mode) throws BytecodeException { 131 value.writeOut(bc, mode); 132 } 133 134 public static void writeOut(final Statement s, BytecodeContext bc) throws BytecodeException { 135 if(ExpressionUtil.doLog(bc)) { 136 final String id=BodyBase.id(); 137 TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() { 138 public void _writeOut(BytecodeContext bc) { 139 ExpressionUtil.callEndLog(bc, s,id); 140 } 141 },null); 142 143 tfv.visitTryBegin(bc); 144 ExpressionUtil.callStartLog(bc, s,id); 145 s.writeOut(bc); 146 tfv.visitTryEnd(bc) ; 147 } 148 else s.writeOut(bc); 149 } 150 151 public static short toShortType(ExprString expr,boolean alsoAlias, short defaultValue) { 152 if(expr instanceof LitString){ 153 return CFTypes.toShort(((LitString)expr).getString(),alsoAlias,defaultValue); 154 } 155 return defaultValue; 156 } 157 158 public static void callStartLog(BytecodeContext bc, Statement s, String id) { 159 call_Log(bc, START, s.getStart(),id); 160 } 161 public static void callEndLog(BytecodeContext bc, Statement s, String id) { 162 call_Log(bc, END, s.getEnd(),id); 163 } 164 165 private static void call_Log(BytecodeContext bc, Method method, Position pos, String id) { 166 if(!bc.writeLog() || pos==null || (StringUtil.indexOfIgnoreCase(bc.getMethod().getName(),"call")==-1))return; 167 try{ 168 GeneratorAdapter adapter = bc.getAdapter(); 169 adapter.loadArg(0); 170 //adapter.checkCast(Types.PAGE_CONTEXT_IMPL); 171 adapter.push(pos.pos); 172 adapter.push(id); 173 adapter.invokeVirtual(Types.PAGE_CONTEXT, method); 174 } 175 catch(Throwable t) { 176 ExceptionUtil.rethrowIfNecessary(t); 177 t.printStackTrace(); 178 } 179 } 180 181 public static boolean doLog(BytecodeContext bc) { 182 return bc.writeLog() && StringUtil.indexOfIgnoreCase(bc.getMethod().getName(),"call")!=-1; 183 } 184}