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    }