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;
020
021import java.util.Iterator;
022import java.util.List;
023import java.util.Stack;
024
025import lucee.commons.lang.StringUtil;
026import lucee.runtime.PageSource;
027import lucee.transformer.Context;
028import lucee.transformer.bytecode.literal.LitString;
029import lucee.transformer.bytecode.visitor.OnFinally;
030
031import org.objectweb.asm.ClassWriter;
032import org.objectweb.asm.commons.GeneratorAdapter;
033import org.objectweb.asm.commons.Method;
034
035public class BytecodeContext implements Context {
036        
037
038        private ClassWriter classWriter;
039        private GeneratorAdapter adapter;
040        private String className;
041        private List<LitString> keys;
042        private int count=0;
043        private Method method;
044        private boolean doSubFunctions=true;
045        private BytecodeContext staticConstr;
046        private BytecodeContext constr;
047        private final boolean suppressWSbeforeArg;
048        private final boolean output;
049        
050        private static long _id=0;
051        private synchronized static String id() {
052                if(_id<0)_id=0;
053                return StringUtil.addZeros(++_id,4);
054        }
055        
056        private String id=id();
057        private Page page;
058        private PageSource source;
059
060        public BytecodeContext(PageSource source,BytecodeContext statConstr,BytecodeContext constr,Page page,List<LitString> keys,ClassWriter classWriter,String className, GeneratorAdapter adapter,
061                        Method method,boolean writeLog, boolean suppressWSbeforeArg, boolean output) {
062                this.classWriter = classWriter;
063                this.className = className;
064                this.writeLog = writeLog;
065                this.adapter = adapter;
066                this.keys = keys;
067                this.method=method;
068                this.staticConstr=statConstr;
069                this.constr=constr;
070                this.page=page;
071                this.suppressWSbeforeArg=suppressWSbeforeArg;
072                this.output=output;
073                if(source!=null)this.source=source;
074                else if(constr!=null)this.source=constr.source;
075                else if(statConstr!=null)this.source=statConstr.source;
076        }
077        
078        public BytecodeContext(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,BytecodeContext bc, GeneratorAdapter adapter,Method method) {
079                this.classWriter = bc.getClassWriter();
080                this.className = bc.getClassName();
081                this.writeLog = bc.writeLog();
082                
083                this.adapter = adapter;
084                this.keys = keys;
085                this.method=method;
086                this.staticConstr=statConstr;
087                this.constr=constr;
088                this.page=bc.getPage();
089                this.suppressWSbeforeArg=bc.suppressWSbeforeArg;
090                this.output=bc.output;
091                this.source=bc.source;
092        }
093        
094        /**
095         * @return the id
096         */
097        public String getId() {
098                return id;
099        }
100        
101        /**
102         * @return the count
103         */
104        public int getCount() {
105                return count;
106        }
107
108        /**
109         * @param count the count to set
110         */
111        public int incCount() {
112                return ++this.count;
113        }
114        public void resetCount() {
115                this.count=0;
116        }
117        /**
118         * @return the adapter
119         */
120        public GeneratorAdapter getAdapter() {
121                return adapter;
122        }
123        /**
124         * @param adapter the adapter to set
125         */
126        public void setAdapter(BytecodeContext bc) {
127                this.adapter = bc.getAdapter();
128        }
129        /**
130         * @return the classWriter
131         */
132        public ClassWriter getClassWriter() {
133                return classWriter;
134        }
135        /**
136         * @param classWriter the classWriter to set
137         */
138        public void setClassWriter(ClassWriter classWriter) {
139                this.classWriter = classWriter;
140        }
141        /**
142         * @return the className
143         */
144        public String getClassName() {
145                return className;
146        }
147        /**
148         * @param className the className to set
149         */
150        public void setClassName(String className) {
151                this.className = className;
152        }
153
154        public synchronized int registerKey(LitString lit)  {
155                int index = keys.indexOf(lit);
156                if(index!=-1)return index;// calls the toString method of litString
157                
158                keys.add(lit);
159                
160                return keys.size()-1;
161        }
162
163        public List<LitString> getKeys() {
164                return keys;
165        }
166
167
168        Stack<OnFinally> tcf=new Stack<OnFinally>();
169        private int currentTag;
170        private int line;
171        private BytecodeContext root;
172        private boolean writeLog;
173        private Stack<OnFinally> insideFinallies=new Stack<OnFinally>();
174        
175        //private static BytecodeContext staticConstr;
176        
177        public void pushOnFinally(OnFinally onFinally) {
178                tcf.push(onFinally);
179        }
180        public void popOnFinally() {
181                tcf.pop();
182        }
183        
184        /*public void pushTryCatchFinallyData(TryCatchFinallyData data) {
185                tcf.push(data);
186        }
187        public void popTryCatchFinallyData() {
188                tcf.pop();
189        }*/
190        
191        public Stack<OnFinally> getOnFinallyStack() {
192                return tcf;
193        }
194
195        /**
196         * @return the method
197         */
198        public Method getMethod() {
199                return method;
200        }
201
202        /**
203         * @return the doSubFunctions
204         */
205        public boolean doSubFunctions() {
206                return doSubFunctions;
207        }
208
209        /**
210         * @param doSubFunctions the doSubFunctions to set
211         * @return 
212         */
213        public boolean changeDoSubFunctions(boolean doSubFunctions) {
214                boolean old=this.doSubFunctions;
215                this.doSubFunctions = doSubFunctions;
216                return old;
217        }
218
219        /**
220         * @return the currentTag
221         */
222        public int getCurrentTag() {
223                return currentTag;
224        }
225
226        /**
227         * @param currentTag the currentTag to set
228         */
229        public void setCurrentTag(int currentTag) {
230                this.currentTag = currentTag;
231        }
232
233        public BytecodeContext getStaticConstructor() {
234                return staticConstr;
235        }
236        public BytecodeContext getConstructor() {
237                return constr;
238        }
239
240        public void visitLineNumber(int line) {
241                this.line=line;
242                getAdapter().visitLineNumber(line,getAdapter().mark());
243        }
244
245        public int getLine() {
246                return line;
247        }
248
249        public BytecodeContext getRoot() {
250                return root;
251        }
252        public void setRoot(BytecodeContext root) {
253                this.root= root;
254        }
255
256        public boolean writeLog() {
257                return this.writeLog;
258        }
259
260        public Page getPage() {
261                return page;
262        }
263        
264        public boolean getSupressWSbeforeArg(){
265                return suppressWSbeforeArg;
266        }
267
268        public boolean getOutput() {
269                return output;
270        }
271
272        public PageSource getPageSource() {
273                return source;
274        }
275
276        public void finallyPush(OnFinally onf) {
277                insideFinallies.push(onf);
278        }
279
280        public OnFinally finallyPop() {
281                return insideFinallies.pop();
282        }
283        
284        
285        public boolean insideFinally(OnFinally onf) {
286                Iterator<OnFinally> it = insideFinallies.iterator();
287                while(it.hasNext()){
288                        if(it.next()==onf) return true;
289                }
290                return false;
291        }
292        
293}