001 package railo.transformer.bytecode; 002 003 import java.util.Iterator; 004 import java.util.LinkedList; 005 import java.util.List; 006 007 import org.objectweb.asm.Opcodes; 008 import org.objectweb.asm.Type; 009 import org.objectweb.asm.commons.GeneratorAdapter; 010 import org.objectweb.asm.commons.Method; 011 012 import railo.transformer.bytecode.expression.Expression; 013 import railo.transformer.bytecode.literal.LitString; 014 import railo.transformer.bytecode.statement.PrintOut; 015 import railo.transformer.bytecode.statement.StatementBase; 016 import railo.transformer.bytecode.util.ASMUtil; 017 import railo.transformer.bytecode.util.ExpressionUtil; 018 import railo.transformer.bytecode.util.Types; 019 020 /** 021 * Base Body implementation 022 */ 023 public class BodyBase extends StatementBase implements Body { 024 025 private static long counter=0; 026 private LinkedList statements=new LinkedList(); 027 private Statement last=null; 028 //private int count=-1; 029 private final static int MAX_STATEMENTS=206; 030 031 /** 032 * Constructor of the class 033 */ 034 public BodyBase() { 035 super(-1,-1); 036 } 037 038 039 /** 040 * 041 * @see railo.transformer.bytecode.Body#addStatement(railo.transformer.bytecode.Statement) 042 */ 043 public void addStatement(Statement statement) { 044 045 if(statement instanceof PrintOut) { 046 Expression expr = ((PrintOut)statement).getExpr(); 047 if(expr instanceof LitString && concatPrintouts(((LitString)expr).getString())) return; 048 } 049 statement.setParent(this); 050 this.statements.add(statement); 051 last=statement; 052 } 053 054 public void addFirst(Statement statement) { 055 statement.setParent(this); 056 this.statements.add(0,statement); 057 } 058 059 public void remove(Statement statement) { 060 statement.setParent(null); 061 this.statements.remove(statement); 062 } 063 064 /** 065 * 066 * @see railo.transformer.bytecode.Body#getStatements() 067 */ 068 public List getStatements() { 069 return statements; 070 } 071 072 /** 073 * 074 * @see railo.transformer.bytecode.Body#moveStatmentsTo(railo.transformer.bytecode.Body) 075 */ 076 public void moveStatmentsTo(Body trg) { 077 Iterator it = statements.iterator(); 078 while(it.hasNext()) { 079 Statement stat=(Statement) it.next(); 080 stat.setParent(trg); 081 trg.getStatements().add(stat); 082 } 083 statements.clear(); 084 } 085 086 public void addPrintOut(String str, int line) { 087 if(concatPrintouts(str)) return; 088 089 last=new PrintOut(new LitString(str,line),line); 090 last.setParent(this); 091 this.statements.add(last); 092 } 093 094 private boolean concatPrintouts(String str) { 095 if(last instanceof PrintOut) { 096 PrintOut po=(PrintOut) last; 097 Expression expr = po.getExpr(); 098 if(expr instanceof LitString) { 099 LitString lit=(LitString)expr; 100 if(lit.getString().length()<1024) { 101 po.setExpr(LitString.toExprString(lit.getString().concat(str),lit.getLine())); 102 return true; 103 } 104 } 105 } 106 return false; 107 } 108 109 public void _writeOut(BytecodeContext bc) throws BytecodeException { 110 writeOut(bc.getStaticConstructor(),bc.getConstructor(),bc.getKeys(),statements, bc); 111 } 112 113 114 115 116 public static void writeOut(BytecodeContext statConstr,BytecodeContext constr,List keys,List<Statement> statements,BytecodeContext bc) throws BytecodeException { 117 GeneratorAdapter adapter = bc.getAdapter(); 118 boolean isOutsideMethod; 119 GeneratorAdapter a=null; 120 Method m; 121 BytecodeContext _bc=bc; 122 Iterator<Statement> it = statements.iterator(); 123 //int lastLine=-1; 124 while(it.hasNext()) { 125 isOutsideMethod=bc.getMethod().getReturnType().equals(Types.VOID); 126 Statement s = it.next(); 127 if(_bc.incCount()>MAX_STATEMENTS && bc.doSubFunctions() && 128 (isOutsideMethod || !s.hasFlowController()) && s.getLine()!=-1) { 129 if(a!=null){ 130 a.returnValue(); 131 a.endMethod(); 132 } 133 //ExpressionUtil.visitLine(bc, s.getLine()); 134 String method= ASMUtil.createOverfowMethod(); 135 ExpressionUtil.visitLine(bc, s.getLine()); 136 //ExpressionUtil.lastLine(bc); 137 m= new Method(method,Types.VOID,new Type[]{Types.PAGE_CONTEXT}); 138 a = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , m, null, new Type[]{Types.THROWABLE}, bc.getClassWriter()); 139 140 141 _bc=new BytecodeContext(statConstr,constr,keys,bc,a,m); 142 if(bc.getRoot()!=null)_bc.setRoot(bc.getRoot()); 143 else _bc.setRoot(bc); 144 145 adapter.visitVarInsn(Opcodes.ALOAD, 0); 146 adapter.visitVarInsn(Opcodes.ALOAD, 1); 147 adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bc.getClassName(), method, "(Lrailo/runtime/PageContext;)V"); 148 } 149 if(_bc!=bc && s.hasFlowController()) { 150 if(a!=null){ 151 a.returnValue(); 152 a.endMethod(); 153 } 154 _bc=bc; 155 a=null; 156 } 157 /* 158 if(s instanceof TagBase){ 159 TagBase tb=(TagBase) s; 160 print.e(tb.getFullname()+":"+s.getClass().getName()+":"+s.getLine()+":"+tb.getStartLine()+":"+tb.getEndLine()); 161 } 162 else print.e(s.getClass().getName()+":"+s.getLine()); 163 */ 164 165 if(ExpressionUtil.doLog(bc)) { 166 String id=id(); 167 ExpressionUtil.callStartLog(bc, s,id); 168 s.writeOut(_bc); 169 ExpressionUtil.callEndLog(bc, s,id); 170 } 171 else s.writeOut(_bc); 172 173 174 } 175 if(a!=null){ 176 a.returnValue(); 177 a.endMethod(); 178 } 179 } 180 181 private static synchronized String id() { 182 counter++; 183 if(counter<0) counter=1; 184 return Long.toString(counter, Character.MAX_RADIX); 185 } 186 187 188 189 /** 190 * 191 * @see railo.transformer.bytecode.Body#isEmpty() 192 */ 193 public boolean isEmpty() { 194 return statements.isEmpty(); 195 } 196 }