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.StatementBaseNoFinal; 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 StatementBaseNoFinal implements Body { 024 025 private static long counter=0; 026 private LinkedList<Statement> statements=new LinkedList<Statement>(); 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(null,null); 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<Statement> getStatements() { 069 return statements; 070 } 071 072 public boolean hasStatements() { 073 return !statements.isEmpty(); 074 } 075 076 /** 077 * 078 * @see railo.transformer.bytecode.Body#moveStatmentsTo(railo.transformer.bytecode.Body) 079 */ 080 public void moveStatmentsTo(Body trg) { 081 Iterator<Statement> it = statements.iterator(); 082 while(it.hasNext()) { 083 Statement stat=it.next(); 084 stat.setParent(trg); 085 trg.getStatements().add(stat); 086 } 087 statements.clear(); 088 } 089 090 public void addPrintOut(String str, Position start,Position end) { 091 if(concatPrintouts(str)) return; 092 093 last=new PrintOut(new LitString(str,start,end),start,end); 094 last.setParent(this); 095 this.statements.add(last); 096 } 097 098 private boolean concatPrintouts(String str) { 099 if(last instanceof PrintOut) { 100 PrintOut po=(PrintOut) last; 101 Expression expr = po.getExpr(); 102 if(expr instanceof LitString) { 103 LitString lit=(LitString)expr; 104 if(lit.getString().length()<1024) { 105 po.setExpr(LitString.toExprString(lit.getString().concat(str),lit.getStart(),lit.getEnd())); 106 return true; 107 } 108 } 109 } 110 return false; 111 } 112 113 public void _writeOut(BytecodeContext bc) throws BytecodeException { 114 writeOut(bc.getStaticConstructor(),bc.getConstructor(),bc.getKeys(),statements, bc); 115 } 116 117 public static void writeOut2(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,List<Statement> statements,BytecodeContext bc) throws BytecodeException { 118 Iterator<Statement> it = statements.iterator(); 119 while(it.hasNext()) { 120 Statement s = it.next(); 121 s.writeOut(bc); 122 } 123 } 124 125 public static void writeOut(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,List<Statement> statements,BytecodeContext bc) throws BytecodeException { 126 GeneratorAdapter adapter = bc.getAdapter(); 127 boolean isOutsideMethod; 128 GeneratorAdapter a=null; 129 Method m; 130 BytecodeContext _bc=bc; 131 Iterator<Statement> it = statements.iterator(); 132 //int lastLine=-1; 133 while(it.hasNext()) { 134 isOutsideMethod=bc.getMethod().getReturnType().equals(Types.VOID); 135 Statement s = it.next(); 136 if(_bc.incCount()>MAX_STATEMENTS && bc.doSubFunctions() && 137 (isOutsideMethod || !s.hasFlowController()) && s.getStart()!=null) { 138 if(a!=null){ 139 a.returnValue(); 140 a.endMethod(); 141 } 142 //ExpressionUtil.visitLine(bc, s.getLine()); 143 String method= ASMUtil.createOverfowMethod(); 144 ExpressionUtil.visitLine(bc, s.getStart()); 145 //ExpressionUtil.lastLine(bc); 146 m= new Method(method,Types.VOID,new Type[]{Types.PAGE_CONTEXT}); 147 a = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , m, null, new Type[]{Types.THROWABLE}, bc.getClassWriter()); 148 149 _bc=new BytecodeContext(statConstr,constr,keys,bc,a,m); 150 if(bc.getRoot()!=null)_bc.setRoot(bc.getRoot()); 151 else _bc.setRoot(bc); 152 153 adapter.visitVarInsn(Opcodes.ALOAD, 0); 154 adapter.visitVarInsn(Opcodes.ALOAD, 1); 155 adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bc.getClassName(), method, "(Lrailo/runtime/PageContext;)V"); 156 } 157 if(_bc!=bc && s.hasFlowController()) { 158 if(a!=null){ 159 a.returnValue(); 160 a.endMethod(); 161 } 162 _bc=bc; 163 a=null; 164 } 165 166 if(ExpressionUtil.doLog(bc)) { 167 String id=id(); 168 ExpressionUtil.callStartLog(bc, s,id); 169 s.writeOut(_bc); 170 ExpressionUtil.callEndLog(bc, s,id); 171 } 172 else s.writeOut(_bc); 173 } 174 if(a!=null){ 175 a.returnValue(); 176 a.endMethod(); 177 } 178 } 179 180 private static synchronized String id() { 181 counter++; 182 if(counter<0) counter=1; 183 return Long.toString(counter, Character.MAX_RADIX); 184 } 185 186 /** 187 * 188 * @see railo.transformer.bytecode.Body#isEmpty() 189 */ 190 public boolean isEmpty() { 191 return statements.isEmpty(); 192 } 193 }