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    }