001    package railo.transformer.bytecode;
002    
003    import java.io.IOException;
004    import java.util.ArrayList;
005    import java.util.Iterator;
006    import java.util.List;
007    import java.util.Map;
008    import java.util.Map.Entry;
009    
010    import org.objectweb.asm.ClassReader;
011    import org.objectweb.asm.ClassVisitor;
012    import org.objectweb.asm.ClassWriter;
013    import org.objectweb.asm.FieldVisitor;
014    import org.objectweb.asm.Label;
015    import org.objectweb.asm.MethodVisitor;
016    import org.objectweb.asm.Opcodes;
017    import org.objectweb.asm.Type;
018    import org.objectweb.asm.commons.GeneratorAdapter;
019    import org.objectweb.asm.commons.Method;
020    
021    import railo.print;
022    import railo.commons.io.res.Resource;
023    import railo.commons.lang.NumberUtil;
024    import railo.commons.lang.StringUtil;
025    import railo.runtime.component.ImportDefintion;
026    import railo.runtime.component.ImportDefintionImpl;
027    import railo.runtime.exp.TemplateException;
028    import railo.runtime.type.KeyImpl;
029    import railo.runtime.type.StructImpl;
030    import railo.runtime.type.UDF;
031    import railo.runtime.type.scope.Undefined;
032    import railo.runtime.type.util.KeyConstants;
033    import railo.transformer.bytecode.expression.Expression;
034    import railo.transformer.bytecode.extern.StringExternalizerWriter;
035    import railo.transformer.bytecode.literal.LitString;
036    import railo.transformer.bytecode.literal.Null;
037    import railo.transformer.bytecode.statement.Argument;
038    import railo.transformer.bytecode.statement.HasBodies;
039    import railo.transformer.bytecode.statement.HasBody;
040    import railo.transformer.bytecode.statement.IFunction;
041    import railo.transformer.bytecode.statement.NativeSwitch;
042    import railo.transformer.bytecode.statement.tag.Attribute;
043    import railo.transformer.bytecode.statement.tag.Tag;
044    import railo.transformer.bytecode.statement.tag.TagImport;
045    import railo.transformer.bytecode.statement.tag.TagThread;
046    import railo.transformer.bytecode.statement.udf.Function;
047    import railo.transformer.bytecode.statement.udf.FunctionImpl;
048    import railo.transformer.bytecode.util.ASMConstants;
049    import railo.transformer.bytecode.util.ASMUtil;
050    import railo.transformer.bytecode.util.ExpressionUtil;
051    import railo.transformer.bytecode.util.Types;
052    import railo.transformer.bytecode.visitor.ArrayVisitor;
053    import railo.transformer.bytecode.visitor.ConditionVisitor;
054    import railo.transformer.bytecode.visitor.DecisionIntVisitor;
055    import railo.transformer.bytecode.visitor.OnFinally;
056    import railo.transformer.bytecode.visitor.TryCatchFinallyVisitor;
057    
058    /**
059     * represent a single Page like "index.cfm"
060     */
061    public final class Page extends BodyBase {
062    
063    
064            public void doFinalize(BytecodeContext bc) {
065                    ExpressionUtil.visitLine(bc, getEnd());
066            }
067            
068            public static final Type NULL = Type.getType(railo.runtime.type.Null.class);
069            public static final Type KEY_IMPL = Type.getType(KeyImpl.class);
070            public static final Type KEY_CONSTANTS = Type.getType(KeyConstants.class);
071            public static final Method KEY_INIT = new Method(
072                            "init",
073                            Types.COLLECTION_KEY,
074                            new Type[]{Types.STRING}
075                    );
076            public static final Method KEY_INTERN = new Method(
077                            "intern",
078                            Types.COLLECTION_KEY,
079                            new Type[]{Types.STRING}
080                    );
081            
082            // public static ImportDefintion getInstance(String fullname,ImportDefintion defaultValue)
083            private static final Method ID_GET_INSTANCE = new Method(
084                            "getInstance",
085                            Types.IMPORT_DEFINITIONS,
086                            new Type[]{Types.STRING,Types.IMPORT_DEFINITIONS}
087                    );
088    
089            public final static Method STATIC_CONSTRUCTOR = Method.getMethod("void <clinit> ()V");
090            //public final static Method CONSTRUCTOR = Method.getMethod("void <init> ()V");
091    
092            private static final Method CONSTRUCTOR = new Method(
093                            "<init>",
094                            Types.VOID,
095                            new Type[]{}//
096                    );
097            private static final Method CONSTRUCTOR_PS = new Method(
098                            "<init>",
099                            Types.VOID,
100                            new Type[]{Types.PAGE_SOURCE}//
101                    );
102    
103        public static final Type STRUCT_IMPL = Type.getType(StructImpl.class);
104            private static final Method INIT_STRUCT_IMPL = new Method(
105                            "<init>",
106                            Types.VOID,
107                            new Type[]{}
108                    );
109    
110            
111        // void call (railo.runtime.PageContext)
112        private final static Method CALL = new Method(
113                            "call",
114                            Types.VOID,
115                            new Type[]{Types.PAGE_CONTEXT}
116                    );
117        
118        /*/ void _try ()
119        private final static Method TRY = new Method(
120                            "_try",
121                            Types.VOID,
122                            new Type[]{}
123                    );*/
124            
125        // int getVersion()
126        private final static Method VERSION = new Method(
127                            "getVersion",
128                            Types.INT_VALUE,
129                            new Type[]{}
130                    );
131        // void _init()
132        private final static Method _INIT = new Method(
133                            "initKeys",
134                            Types.VOID,
135                            new Type[]{}
136                    );
137        
138        private final static Method SET_PAGE_SOURCE = new Method(
139                            "setPageSource",
140                            Types.VOID,
141                            new Type[]{Types.PAGE_SOURCE}
142                    );
143        
144        // public ImportDefintion[] getImportDefintions()
145        private final static Method GET_IMPORT_DEFINITIONS = new Method(
146                            "getImportDefintions",
147                            Types.IMPORT_DEFINITIONS_ARRAY,
148                            new Type[]{}
149                    );
150        
151        // long getSourceLastModified()
152        private final static Method LAST_MOD = new Method(
153                            "getSourceLastModified",
154                            Types.LONG_VALUE,
155                            new Type[]{}
156                    );
157        
158        private final static Method COMPILE_TIME = new Method(
159                            "getCompileTime",
160                            Types.LONG_VALUE,
161                            new Type[]{}
162                    );
163    
164        private static final Type USER_DEFINED_FUNCTION = Type.getType(UDF.class);
165        private static final Method UDF_CALL = new Method(
166                            "udfCall",
167                            Types.OBJECT,
168                            new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE}
169                            );
170        
171    
172            private static final Method THREAD_CALL = new Method(
173                            "threadCall",
174                            Types.VOID,
175                            new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE}
176                            );
177    
178            /*private static final Method UDF_DEFAULT_VALUE = new Method(
179                            "udfDefaultValue",
180                            Types.OBJECT,
181                            new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE}
182                            );*/
183            
184            private static final Method UDF_DEFAULT_VALUE = new Method(
185                            "udfDefaultValue",
186                            Types.OBJECT,
187                            new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT}
188                            );
189    
190            private static final Method NEW_COMPONENT_IMPL_INSTANCE = new Method(
191                            "newInstance",
192                            Types.COMPONENT_IMPL,
193                            new Type[]{Types.PAGE_CONTEXT,Types.STRING,Types.BOOLEAN_VALUE}
194                    );
195            
196            private static final Method NEW_INTERFACE_IMPL_INSTANCE = new Method(
197                            "newInstance",
198                            Types.INTERFACE_IMPL,
199                            new Type[]{Types.STRING,Types.BOOLEAN_VALUE,Types.MAP}
200                    );
201            
202            
203    
204            
205    
206            // void init(PageContext pc,Component Impl c) throws PageException
207            private static final Method INIT_COMPONENT = new Method(
208                            "initComponent",
209                            Types.VOID,
210                            new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_IMPL}
211                    );
212            private static final Method INIT_INTERFACE = new Method(
213                            "initInterface",
214                            Types.VOID,
215                            new Type[]{Types.INTERFACE_IMPL}
216                    );
217            
218    
219            // public boolean setMode(int mode) {
220            private static final Method SET_MODE = new Method(
221                            "setMode",
222                            Types.INT_VALUE,
223                            new Type[]{Types.INT_VALUE}
224                    );
225            
226            
227    
228    
229            
230            
231    
232    
233            private static final Method CONSTR_INTERFACE_IMPL = new Method(
234                            "<init>",
235                            Types.VOID,
236                            new Type[]{
237                                            Types.INTERFACE_PAGE,
238                                                    Types.STRING, // extends
239                                                    Types.STRING, // hind
240                                                    Types.STRING, // display
241                                                    Types.STRING, // callpath
242                                                    Types.BOOLEAN_VALUE, // realpath
243                                                    Types.MAP, //interfaceudfs
244                                                    Types.MAP // meta
245                                            }
246                    );
247            
248            
249            //void init(PageContext pageContext,ComponentPage componentPage)
250            private static final Method INIT = new Method(
251                            "init",
252                            Types.VOID,
253                            new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE}
254                    );
255            
256            private static final Method CHECK_INTERFACE = new Method(
257                            "checkInterface",
258                            Types.VOID,
259                            new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE}
260                    );
261            
262            
263    
264            // boolean getOutput()
265            private static final Method GET_OUTPUT = new Method(
266                            "getOutput",
267                            Types.BOOLEAN_VALUE,
268                            new Type[]{}
269                    );
270    
271    
272            private static final Method PUSH_BODY = new Method(
273                            "pushBody",
274                            Types.BODY_CONTENT,
275                            new Type[]{}
276                    );
277            
278            /*/ boolean setSilent()
279            private static final Method SET_SILENT = new Method(
280                            "setSilent",
281                            Types.BOOLEAN_VALUE,
282                            new Type[]{}
283                    );
284    */
285            // Scope beforeCall(PageContext pc)
286            private static final Method BEFORE_CALL = new Method(
287                            "beforeCall",
288                            Types.VARIABLES,
289                            new Type[]{Types.PAGE_CONTEXT}
290                    );
291    
292            private static final Method TO_PAGE_EXCEPTION = new Method(
293                            "toPageException",
294                            Types.PAGE_EXCEPTION,
295                            new Type[]{Types.THROWABLE});
296            
297            
298            // boolean unsetSilent()
299            /*private static final Method UNSET_SILENT = new Method(
300                            "unsetSilent",
301                            Types.BOOLEAN_VALUE,
302                            new Type[]{}
303                    );*/
304    
305            // void afterCall(PageContext pc, Scope parent)
306            private static final Method AFTER_CALL = new Method(
307                            "afterConstructor",
308                            Types.VOID,
309                            new Type[]{Types.PAGE_CONTEXT,Types.VARIABLES}
310                    );
311    
312            // ComponentImpl(ComponentPage,boolean, String, String, String) NS==No Style
313            
314            
315            // Component Impl(ComponentPage,boolean, String, String, String, String) WS==With Style
316            private static final Method CONSTR_COMPONENT_IMPL = new Method(
317                            "<init>",
318                            Types.VOID,
319                            new Type[]{
320                                            Types.COMPONENT_PAGE,
321                                            Types.BOOLEAN,
322                                            Types.BOOLEAN_VALUE,
323                                            Types.STRING,
324                                            Types.STRING,
325                                            Types.STRING,
326                                            Types.STRING,
327                                            Types.STRING,
328                                            Types.BOOLEAN_VALUE,
329                                            Types.STRING,
330                                            Types.BOOLEAN_VALUE,
331                                            Types.BOOLEAN_VALUE,
332                                            STRUCT_IMPL
333                                    }
334                    );
335            private static final Method SET_EL = new Method(
336                            "setEL",
337                            Types.OBJECT,
338                            new Type[]{Types.STRING,Types.OBJECT}
339                    );
340            private static final Method UNDEFINED_SCOPE = new Method(
341                            "us",
342                            Types.UNDEFINED,
343                            new Type[]{}
344                    );
345            private static final Method FLUSH_AND_POP = new Method(
346                            "flushAndPop",
347                            Types.VOID,
348                            new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT}
349                    );
350            private static final Method CLEAR_AND_POP = new Method(
351                            "clearAndPop",
352                            Types.VOID,
353                            new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT}
354                    );
355            public static final byte CF = (byte)207;
356            public static final byte _33 = (byte)51;
357            private static final boolean ADD_C33 = false;
358            //private static final String SUB_CALL_UDF = "udfCall";
359            private static final String SUB_CALL_UDF = "_";
360            private static final int DEFAULT_VALUE = 3;
361                    
362        private int version;
363        private long lastModifed;
364        private String name;
365        
366        //private Body body=new Body();
367            private Resource source;
368            private final String path;
369            private boolean isComponent;
370            private boolean isInterface;
371    
372            private List<IFunction> functions=new ArrayList<IFunction>();
373            private List<TagThread> threads=new ArrayList<TagThread>();
374            private boolean _writeLog;
375            private StringExternalizerWriter externalizer;
376            private boolean supressWSbeforeArg;
377        
378            
379            
380        public Page(Resource source,String name,int version, long lastModifed, boolean writeLog, boolean supressWSbeforeArg) {
381            name=name.replace('.', '/');
382            //body.setParent(this);
383            this.name=name;
384            this.version=version;
385            this.lastModifed=lastModifed;
386            this.source=source;
387            this.path=source.getAbsolutePath();
388            
389            this._writeLog=writeLog;
390            this.supressWSbeforeArg=supressWSbeforeArg;
391        }
392        
393        /**
394         * result byte code as binary array
395         * @param classFile 
396         * @return byte code
397         * @throws IOException 
398         * @throws TemplateException 
399         */
400        public byte[] execute(Resource classFile) throws BytecodeException {
401            
402            Resource p = classFile.getParentResource().getRealResource(classFile.getName()+".txt");
403            this.externalizer=new StringExternalizerWriter(p);
404                    
405            List<LitString> keys=new ArrayList<LitString>();
406            ClassWriter cw = ASMUtil.getClassWriter(); 
407            //ClassWriter cw = new ClassWriter(true);
408            
409            ArrayList<String> imports = new ArrayList<String>();
410            getImports(imports, this); 
411            
412            // parent
413            String parent="railo/runtime/PagePlus";
414            if(isComponent()) parent="railo/runtime/ComponentPage";
415            else if(isInterface()) parent="railo/runtime/InterfacePage";
416            
417            cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL, name, null, parent, null);
418            cw.visitSource(this.path, null);
419    
420            // static constructor
421            //GeneratorAdapter statConstrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,STATIC_CONSTRUCTOR,null,null,cw);
422                    BytecodeContext statConstr = null;//new BytecodeContext(null,null,this,externalizer,keys,cw,name,statConstrAdapter,STATIC_CONSTRUCTOR,writeLog(),supressWSbeforeArg);
423                    
424            // constructor
425                GeneratorAdapter constrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_PS,null,null,cw);
426                    BytecodeContext constr = new BytecodeContext(null,null,this,externalizer,keys,cw,name,constrAdapter,CONSTRUCTOR_PS,writeLog(),supressWSbeforeArg);
427                    constrAdapter.loadThis();
428            Type t=Types.PAGE_PLUS;
429            if(isComponent())t=Types.COMPONENT_PAGE;
430            else if(isInterface())t=Types.INTERFACE_PAGE;
431            
432            constrAdapter.invokeConstructor(t, CONSTRUCTOR);
433            
434         // call _init()
435            constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
436            constrAdapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, constr.getClassName(), "initKeys", "()V");
437    
438         // private static  ImportDefintion[] test=new ImportDefintion[]{...};
439                {
440                            FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, 
441                                            "imports", "[Lrailo/runtime/component/ImportDefintion;", null, null);
442                            fv.visitEnd();
443                    
444                            constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
445                            ArrayVisitor av=new ArrayVisitor();
446                            av.visitBegin(constrAdapter,Types.IMPORT_DEFINITIONS,imports.size());
447                            int index=0;
448                            Iterator<String> it = imports.iterator();
449                            while(it.hasNext()){
450                                    av.visitBeginItem(constrAdapter,index++);
451                                    constrAdapter.push(it.next());
452                                    ASMConstants.NULL(constrAdapter);
453                                    constrAdapter.invokeStatic(Types.IMPORT_DEFINITIONS_IMPL, ID_GET_INSTANCE);
454                                    av.visitEndItem(constrAdapter);
455                            }
456                            av.visitEnd();
457                            constrAdapter.visitFieldInsn(Opcodes.PUTFIELD, name, "imports", "[Lrailo/runtime/component/ImportDefintion;");
458                                    
459                    }
460            
461            
462            
463            
464         // getVersion
465             GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , VERSION, null, null, cw);
466             adapter.push(version);
467             adapter.returnValue();
468             adapter.endMethod();
469             
470             
471        // public ImportDefintion[] getImportDefintions()
472             if(imports.size()>0){
473                     adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw);
474                     adapter.visitVarInsn(Opcodes.ALOAD, 0);
475                 adapter.visitFieldInsn(Opcodes.GETFIELD, name, "imports", "[Lrailo/runtime/component/ImportDefintion;");
476                     adapter.returnValue();
477                 adapter.endMethod();
478             }
479             else {
480                     adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw);
481                     adapter.visitInsn(Opcodes.ICONST_0);
482                     adapter.visitTypeInsn(Opcodes.ANEWARRAY, "railo/runtime/component/ImportDefintion");
483                     adapter.returnValue();
484                 adapter.endMethod();
485             }
486    
487             
488        // getSourceLastModified
489            adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , LAST_MOD, null, null, cw);
490            adapter.push(lastModifed);
491            adapter.returnValue();
492            adapter.endMethod();
493            
494        // getCompileTime
495            adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , COMPILE_TIME, null, null, cw);
496            adapter.push(System.currentTimeMillis());
497            adapter.returnValue();
498            adapter.endMethod();
499       
500        // newInstance/initComponent/call
501            if(isComponent()) {
502                    Tag component=getComponent();
503                    writeOutNewComponent(statConstr,constr,keys,cw,component);
504                    writeOutInitComponent(statConstr,constr,keys,cw,component);
505            }
506            else if(isInterface()) {
507                    Tag interf=getInterface();
508                    writeOutNewInterface(statConstr,constr,keys,cw,interf);
509                    writeOutInitInterface(statConstr,constr,keys,cw,interf);
510            }
511            else {
512                    writeOutCall(statConstr,constr,keys,cw);
513            }
514            
515    // udfCall     
516            Function[] functions=getFunctions();
517            ConditionVisitor cv;
518            DecisionIntVisitor div;
519        // less/equal than 10 functions
520            if(isInterface()){}
521            else if(functions.length<=10) {
522                    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw);
523                BytecodeContext bc = new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,UDF_CALL,writeLog(),supressWSbeforeArg);
524                if(functions.length==0){}
525                else if(functions.length==1){
526                            ExpressionUtil.visitLine(bc,functions[0].getStart());
527                            functions[0].getBody().writeOut(bc);
528                            ExpressionUtil.visitLine(bc,functions[0].getEnd());
529                    }
530                    else writeOutUdfCallInner(bc,functions,0,functions.length);
531                adapter.visitInsn(Opcodes.ACONST_NULL);
532                adapter.returnValue();
533                adapter.endMethod(); 
534            }
535       // more than 10 functions
536            else {
537                    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw);
538                    BytecodeContext bc = new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,UDF_CALL,writeLog(),supressWSbeforeArg);
539                            cv = new ConditionVisitor();
540                            cv.visitBefore();
541                            int count=0;
542                            for(int i=0;i<functions.length;i+=10) {
543                                    cv.visitWhenBeforeExpr();
544                                            div=new DecisionIntVisitor();
545                                                    div.visitBegin();
546                                                            adapter.loadArg(2);
547                                                    div.visitLT();
548                                                            adapter.push(i+10);
549                                                    div.visitEnd(bc);
550                                    cv.visitWhenAfterExprBeforeBody(bc);
551                                            
552                                            adapter.visitVarInsn(Opcodes.ALOAD, 0);
553                                            adapter.visitVarInsn(Opcodes.ALOAD, 1);
554                                            adapter.visitVarInsn(Opcodes.ALOAD, 2);
555                                            adapter.visitVarInsn(Opcodes.ILOAD, 3);
556                                            adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, createFunctionName(++count), "(Lrailo/runtime/PageContext;Lrailo/runtime/type/UDF;I)Ljava/lang/Object;");
557                                            adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue();
558                                    cv.visitWhenAfterBody(bc);
559                            }
560                            cv.visitAfter(bc);
561                    
562                    adapter.visitInsn(Opcodes.ACONST_NULL);
563                    adapter.returnValue();
564                    adapter.endMethod();
565                    
566                    count=0;
567                    Method innerCall;
568                    for(int i=0;i<functions.length;i+=10) {
569                            innerCall = new Method(createFunctionName(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE});
570                            
571                            adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerCall, null, new Type[]{Types.THROWABLE}, cw);
572                            writeOutUdfCallInner(new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,innerCall,writeLog(),supressWSbeforeArg), functions, i, i+10>functions.length?functions.length:i+10);
573                            
574                            adapter.visitInsn(Opcodes.ACONST_NULL);
575                            adapter.returnValue();
576                            adapter.endMethod();
577                    }
578            }
579            
580    
581         // threadCall
582             TagThread[] threads=getThreads();
583             if(true) {
584                    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , THREAD_CALL, null, new Type[]{Types.THROWABLE}, cw);
585                    if(threads.length>0) writeOutThreadCallInner(new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,THREAD_CALL,writeLog(),supressWSbeforeArg),threads,0,threads.length);
586                    //adapter.visitInsn(Opcodes.ACONST_NULL);
587                    adapter.returnValue();
588                    adapter.endMethod();
589             }
590            
591    
592            
593                    
594    // udfDefaultValue
595        // less/equal than 10 functions
596            if(isInterface()) {}
597            else if(functions.length<=10) {
598                    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
599                    if(functions.length>0)
600                            writeUdfDefaultValueInner(new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),supressWSbeforeArg),functions,0,functions.length);
601                
602                adapter.loadArg(DEFAULT_VALUE);
603                    adapter.returnValue();
604                adapter.endMethod();
605            }
606            else {
607                    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
608                BytecodeContext bc = new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),supressWSbeforeArg);
609                    cv = new ConditionVisitor();
610                    cv.visitBefore();
611                    int count=0;
612                    for(int i=0;i<functions.length;i+=10) {
613                            cv.visitWhenBeforeExpr();
614                                    div=new DecisionIntVisitor();
615                                            div.visitBegin();
616                                                    adapter.loadArg(1);
617                                            div.visitLT();
618                                                    adapter.push(i+10);
619                                            div.visitEnd(bc);
620                            cv.visitWhenAfterExprBeforeBody(bc);
621                                    
622                                    adapter.visitVarInsn(Opcodes.ALOAD, 0);
623                                    adapter.visitVarInsn(Opcodes.ALOAD, 1);
624                                    adapter.visitVarInsn(Opcodes.ILOAD, 2);
625                                    adapter.visitVarInsn(Opcodes.ILOAD, 3);
626                                    adapter.visitVarInsn(Opcodes.ALOAD, 4);
627                                    
628                                    adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, "udfDefaultValue"+(++count), "(Lrailo/runtime/PageContext;IILjava/lang/Object;)Ljava/lang/Object;");
629                                    adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue();
630                                    
631                            cv.visitWhenAfterBody(bc);
632                    }
633                    cv.visitAfter(bc);
634            
635            adapter.visitInsn(Opcodes.ACONST_NULL);
636            adapter.returnValue();
637            adapter.endMethod();
638            
639            count=0;
640            Method innerDefaultValue;
641            for(int i=0;i<functions.length;i+=10) {
642                    innerDefaultValue = new Method("udfDefaultValue"+(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT});
643                    adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerDefaultValue, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
644                    writeUdfDefaultValueInner(new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,adapter,innerDefaultValue,writeLog(),supressWSbeforeArg), functions, i, i+10>functions.length?functions.length:i+10);
645                    
646                    adapter.loadArg(DEFAULT_VALUE);
647                    //adapter.visitInsn(Opcodes.ACONST_NULL);
648                    adapter.returnValue();
649                    adapter.endMethod();
650            }
651                    
652            }
653            
654            
655            // register fields
656            {
657                    GeneratorAdapter aInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , _INIT, null, null, cw);
658                BytecodeContext bcInit = new BytecodeContext(statConstr,constr,this,externalizer,keys,cw,name,aInit,_INIT,writeLog(),supressWSbeforeArg);
659                    registerFields(bcInit,keys);
660                    aInit.returnValue();
661                    aInit.endMethod();
662            }
663    
664            //setPageSource(pageSource);
665            constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
666            constrAdapter.visitVarInsn(Opcodes.ALOAD, 1);
667            constrAdapter.invokeVirtual(t, SET_PAGE_SOURCE);
668            
669            
670    
671            //statConstr.getAdapter().returnValue();
672            //statConstr.getAdapter().endMethod();
673            
674            
675            constrAdapter.returnValue();
676            constrAdapter.endMethod();
677            
678            try {
679                            if(externalizer!=null)externalizer.writeOut();
680                    } catch (IOException e) {
681                            throw new BytecodeException(e.getMessage(), null);
682                    }
683            
684            
685            if(ADD_C33) {
686                    byte[] tmp = cw.toByteArray();
687                    byte[] bLastMod=NumberUtil.longToByteArray(lastModifed);
688                    byte[] barr = new byte[tmp.length+10];
689                    // Magic Number
690                    barr[0]=CF; // CF
691                    barr[1]=_33; // 33
692                    
693                    // Last Modified
694                    for(int i=0;i<8;i++){
695                            barr[i+2]=bLastMod[i];
696                    }
697                    for(int i=0;i<tmp.length;i++){
698                            barr[i+10]=tmp[i];
699                    }
700                    return barr;
701            }
702            return cw.toByteArray();
703            
704        }
705        
706    
707    
708    
709            private String createFunctionName(int i) {
710                    return "_"+Integer.toString(i, Character.MAX_RADIX);
711            }
712    
713            private boolean writeLog() {
714                    return _writeLog && !isInterface();
715            }
716    
717            public static void registerFields(BytecodeContext bc, List<LitString> keys) throws BytecodeException {
718                    //if(keys.size()==0) return;
719                    GeneratorAdapter ga = bc.getAdapter();
720                    
721                    FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE ,
722                                    "keys", Types.COLLECTION_KEY_ARRAY.toString(), null, null);
723                    fv.visitEnd();
724                    
725                    int index=0;
726                    LitString value;
727                    Iterator<LitString> it = keys.iterator();
728                    ga.visitVarInsn(Opcodes.ALOAD, 0);
729                    ga.push(keys.size());
730                    ga.newArray(Types.COLLECTION_KEY);
731                    while(it.hasNext()) {
732                            value=it.next();
733                            ga.dup();
734                            ga.push(index++);
735                            ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF);
736                            ga.invokeStatic(KEY_IMPL, KEY_INTERN);
737                            ga.visitInsn(Opcodes.AASTORE);
738                    }
739                    ga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "keys", Types.COLLECTION_KEY_ARRAY.toString());
740            }
741    
742            private void writeUdfDefaultValueInner(BytecodeContext bc, Function[] functions, int offset, int length) throws BytecodeException {
743                    GeneratorAdapter adapter = bc.getAdapter();
744                    ConditionVisitor cv = new ConditionVisitor();
745                    DecisionIntVisitor div;
746            cv.visitBefore();
747            for(int i=offset;i<length;i++) {
748                    cv.visitWhenBeforeExpr();
749                            div = new DecisionIntVisitor();
750                                    div.visitBegin();
751                                            adapter.loadArg(1);
752                                    div.visitEQ();
753                                            adapter.push(i);
754                                    div.visitEnd(bc);
755                    cv.visitWhenAfterExprBeforeBody(bc);
756                            writeOutFunctionDefaultValueInnerInner(bc, functions[i]);
757                    cv.visitWhenAfterBody(bc);
758            }
759            cv.visitAfter(bc);
760            }
761    
762    
763            private void writeOutUdfCallInnerIf(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException {
764                    GeneratorAdapter adapter = bc.getAdapter();
765                    ConditionVisitor cv=new ConditionVisitor();
766            DecisionIntVisitor div;
767            cv.visitBefore();
768            for(int i=offset;i<length;i++) {
769                    cv.visitWhenBeforeExpr();
770                            div=new DecisionIntVisitor();
771                                    div.visitBegin();
772                                            adapter.loadArg(2);
773                                    div.visitEQ();
774                                            adapter.push(i);
775                                    div.visitEnd(bc);
776                    cv.visitWhenAfterExprBeforeBody(bc);
777                            ExpressionUtil.visitLine(bc, functions[i].getStart());
778                            functions[i].getBody().writeOut(bc);
779                            ExpressionUtil.visitLine(bc, functions[i].getEnd());
780                    cv.visitWhenAfterBody(bc);
781            }
782            cv.visitAfter(bc);
783            }
784    
785            private void writeOutUdfCallInner(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException {
786                    NativeSwitch ns=new NativeSwitch(2,NativeSwitch.ARG_REF,null,null);
787                    
788                    for(int i=offset;i<length;i++) {
789                    ns.addCase(i, functions[i].getBody(),functions[i].getStart(),functions[i].getEnd(),true);
790            }
791            ns._writeOut(bc);
792            }
793            
794            
795    
796            private void writeOutThreadCallInner(BytecodeContext bc,TagThread[] threads, int offset, int length) throws BytecodeException {
797                    GeneratorAdapter adapter = bc.getAdapter();
798                    ConditionVisitor cv=new ConditionVisitor();
799            DecisionIntVisitor div;
800            cv.visitBefore();
801            //print.ln("functions:"+functions.length);
802                    for(int i=offset;i<length;i++) {
803                            cv.visitWhenBeforeExpr();
804                                    div=new DecisionIntVisitor();
805                                            div.visitBegin();
806                                                    adapter.loadArg(1);
807                                            div.visitEQ();
808                                                    adapter.push(i);
809                                            div.visitEnd(bc);
810                            cv.visitWhenAfterExprBeforeBody(bc);
811                                    Body body = threads[i].getRealBody();
812                                    if(body!=null)body.writeOut(bc);
813                            cv.visitWhenAfterBody(bc);
814                    }
815            cv.visitAfter(bc);
816            }
817    
818            private void writeOutInitComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag component) throws BytecodeException {
819                    final GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_COMPONENT, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
820            BytecodeContext bc=new BytecodeContext(statConstr, constr,this,externalizer,keys,cw,name,adapter,INIT_COMPONENT,writeLog(),supressWSbeforeArg);
821                    Label methodBegin=new Label();
822            Label methodEnd=new Label();
823    
824                    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
825            adapter.visitLabel(methodBegin);
826            
827                    // Scope oldData=null;
828                    final int oldData=adapter.newLocal(Types.VARIABLES);
829                    ASMConstants.NULL(adapter);
830                    adapter.storeLocal(oldData);
831                    
832                    int localBC=adapter.newLocal(Types.BODY_CONTENT);
833                    ConditionVisitor cv=new ConditionVisitor();
834                    cv.visitBefore();
835                            cv.visitWhenBeforeExpr();
836                                    adapter.loadArg(1);
837                                    adapter.invokeVirtual(Types.COMPONENT_IMPL, GET_OUTPUT);
838                            cv.visitWhenAfterExprBeforeBody(bc);
839                                    ASMConstants.NULL(adapter);
840                            cv.visitWhenAfterBody(bc);
841    
842                            cv.visitOtherviseBeforeBody();
843                                    adapter.loadArg(0);
844                                    adapter.invokeVirtual(Types.PAGE_CONTEXT, PUSH_BODY);
845                            cv.visitOtherviseAfterBody();
846                    cv.visitAfter(bc);
847                    adapter.storeLocal(localBC);
848                    
849                    // c.init(pc,this);
850                    adapter.loadArg(1);
851                    adapter.loadArg(0);
852                    adapter.visitVarInsn(Opcodes.ALOAD, 0);
853                    adapter.invokeVirtual(Types.COMPONENT_IMPL, INIT);
854                            
855                            
856                    //int oldCheckArgs=     pc.undefinedScope().setMode(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS);
857                            final int oldCheckArgs = adapter.newLocal(Types.INT_VALUE);
858                            adapter.loadArg(0);
859                            adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE);
860                            adapter.push(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS);
861                            adapter.invokeInterface(Types.UNDEFINED, SET_MODE);
862                            adapter.storeLocal(oldCheckArgs);
863                    
864                            
865                    TryCatchFinallyVisitor tcf=new TryCatchFinallyVisitor(new OnFinally() {
866                            
867                            public void writeOut(BytecodeContext bc) {
868    
869                                    // undefined.setMode(oldMode);
870                                    adapter.loadArg(0);
871                                    adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE);
872                                    adapter.loadLocal(oldCheckArgs,Types.INT_VALUE);
873                                    adapter.invokeInterface(Types.UNDEFINED, SET_MODE);
874                                    adapter.pop();
875                                    
876                                            // c.afterCall(pc,_oldData);
877                                            adapter.loadArg(1);
878                                            adapter.loadArg(0);
879                                            adapter.loadLocal(oldData);
880                                            adapter.invokeVirtual(Types.COMPONENT_IMPL, AFTER_CALL);
881                                    
882                                    
883                            }
884                    },null);
885                    tcf.visitTryBegin(bc);
886                            // oldData=c.beforeCall(pc);
887                            adapter.loadArg(1);
888                            adapter.loadArg(0);
889                            adapter.invokeVirtual(Types.COMPONENT_IMPL, BEFORE_CALL);
890                            adapter.storeLocal(oldData);
891                            ExpressionUtil.visitLine(bc, component.getStart());
892                            writeOutCallBody(bc,component.getBody(),IFunction.PAGE_TYPE_COMPONENT);
893                            ExpressionUtil.visitLine(bc, component.getEnd());
894                    int t = tcf.visitTryEndCatchBeging(bc);
895                            // BodyContentUtil.flushAndPop(pc,bc);
896                            adapter.loadArg(0);
897                            adapter.loadLocal(localBC);
898                            adapter.invokeStatic(Types.BODY_CONTENT_UTIL, FLUSH_AND_POP);
899                    
900                            // throw Caster.toPageException(t);
901                            adapter.loadLocal(t);
902                            adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION);
903                            adapter.throwException();
904                    tcf.visitCatchEnd(bc);
905                    
906                    adapter.loadArg(0);
907                    adapter.loadLocal(localBC);
908                    adapter.invokeStatic(Types.BODY_CONTENT_UTIL, CLEAR_AND_POP);
909            
910            adapter.returnValue();
911                adapter.visitLabel(methodEnd);
912                
913                adapter.endMethod();
914            
915            }
916            
917            private void writeOutInitInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag interf) throws BytecodeException {
918                    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_INTERFACE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
919            BytecodeContext bc=new BytecodeContext(statConstr, constr,this,externalizer,keys,cw,name,adapter,INIT_INTERFACE,writeLog(),supressWSbeforeArg);
920                    Label methodBegin=new Label();
921            Label methodEnd=new Label();
922    
923                    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
924            adapter.visitLabel(methodBegin);
925            
926            ExpressionUtil.visitLine(bc, interf.getStart());
927                    writeOutCallBody(bc,interf.getBody(),IFunction.PAGE_TYPE_INTERFACE);
928                    ExpressionUtil.visitLine(bc, interf.getEnd());
929                    
930            adapter.returnValue();
931                adapter.visitLabel(methodEnd);
932                
933                adapter.endMethod();
934            
935            }
936    
937            private Tag getComponent() throws BytecodeException {
938                    Iterator it = getStatements().iterator();
939                    Statement s;
940                    Tag t;
941            while(it.hasNext()) {
942                    s=(Statement)it.next();
943                    if(s instanceof Tag) {
944                            t=(Tag)s;
945                            if(t.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Component"))return t;
946                    }
947            }
948                    throw new BytecodeException("missing component",getStart());
949            }
950            private Tag getInterface() throws BytecodeException {
951                    Iterator it = getStatements().iterator();
952                    Statement s;
953                    Tag t;
954            while(it.hasNext()) {
955                    s=(Statement)it.next();
956                    if(s instanceof Tag) {
957                            t=(Tag)s;
958                            if(t.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Interface"))return t;
959                    }
960            }
961                    throw new BytecodeException("missing interface",getStart());
962            }
963    
964            private void writeOutFunctionDefaultValueInnerInner(BytecodeContext bc, Function function) throws BytecodeException {
965                    GeneratorAdapter adapter = bc.getAdapter();
966                    
967                    List<Argument> args = function.getArguments();
968                    
969                    if(args.size()==0) {
970                            adapter.loadArg(DEFAULT_VALUE);
971                            adapter.returnValue();
972                            return;
973                    }
974                            
975                    Iterator<Argument> it = args.iterator();
976                    Argument arg;
977                    ConditionVisitor cv=new ConditionVisitor();
978                    DecisionIntVisitor div;
979                    cv.visitBefore();
980                    int count=0;
981                    while(it.hasNext()) {
982                            arg=it.next();
983                            cv.visitWhenBeforeExpr();
984                                    div=new DecisionIntVisitor();
985                                    div.visitBegin();
986                                            adapter.loadArg(2);
987                                    div.visitEQ();
988                                            adapter.push(count++);
989                                    div.visitEnd(bc);
990                            cv.visitWhenAfterExprBeforeBody(bc);
991                                    Expression defaultValue = arg.getDefaultValue();
992                                    if(defaultValue!=null) {
993                                            /*if(defaultValue instanceof Null) {
994                                                    adapter.invokeStatic(NULL, GET_INSTANCE);
995                                            }
996                                            else*/ 
997                                            defaultValue.writeOut(bc, Expression.MODE_REF);
998                                    }
999                                    else 
1000                                            adapter.loadArg(DEFAULT_VALUE);
1001                                            //adapter.visitInsn(Opcodes.ACONST_NULL);
1002                                    adapter.returnValue();
1003                            cv.visitWhenAfterBody(bc);
1004                    }
1005                    cv.visitOtherviseBeforeBody();
1006                            //adapter.visitInsn(ACONST_NULL);
1007                            //adapter.returnValue();
1008                    cv.visitOtherviseAfterBody();
1009                    cv.visitAfter(bc);
1010            }
1011    
1012            private Function[] getFunctions() {
1013                    Function[] funcs=new Function[functions.size()];
1014                    Iterator it = functions.iterator();
1015                    int count=0;
1016                    while(it.hasNext()) {
1017                            funcs[count++]=(Function) it.next();
1018                    }
1019                    return funcs;
1020            }
1021            
1022            private TagThread[] getThreads() {
1023                    TagThread[] threads=new TagThread[this.threads.size()];
1024                    Iterator it = this.threads.iterator();
1025                    int count=0;
1026                    while(it.hasNext()) {
1027                            threads[count++]=(TagThread) it.next();
1028                    }
1029                    return threads;
1030            }
1031            
1032            
1033            public void _writeOut(BytecodeContext bc) throws BytecodeException {
1034                    
1035            }
1036    
1037            private void writeOutNewComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag component) throws BytecodeException {
1038                    
1039                    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_COMPONENT_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
1040            BytecodeContext bc=new BytecodeContext(statConstr, constr,this,externalizer,keys,cw,name,adapter,NEW_COMPONENT_IMPL_INSTANCE,writeLog(),supressWSbeforeArg);
1041            Label methodBegin=new Label();
1042            Label methodEnd=new Label();
1043            
1044                    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
1045            adapter.visitLabel(methodBegin);
1046    
1047            //ExpressionUtil.visitLine(adapter, component.getStartLine());
1048            
1049                    int comp=adapter.newLocal(Types.COMPONENT_IMPL);
1050                    adapter.newInstance(Types.COMPONENT_IMPL);
1051                    adapter.dup();
1052                    
1053                    Attribute attr;
1054                    // ComponentPage
1055                    adapter.visitVarInsn(Opcodes.ALOAD, 0);
1056                    adapter.checkCast(Types.COMPONENT_PAGE);
1057    
1058                    // !!! also check CFMLScriptTransformer.addMetaData if you do any change here !!!
1059                    
1060                    // Output
1061                    attr = component.removeAttribute("output");
1062                    if(attr!=null) {
1063                            ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1064                    }
1065                    else ASMConstants.NULL(adapter);
1066    
1067                    // synchronized 
1068                    attr = component.removeAttribute("synchronized");
1069                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE);
1070                    else adapter.push(false);
1071    
1072                    // extends
1073                    attr = component.removeAttribute("extends");
1074                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1075                    else adapter.push("");
1076     
1077                    // implements
1078                    attr = component.removeAttribute("implements");
1079                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1080                    else adapter.push("");
1081                    
1082                    // hint
1083                    attr = component.removeAttribute("hint");
1084                    if(attr!=null) {
1085                            Expression value = attr.getValue();
1086                            if(!(value instanceof Literal)){
1087                                    value=LitString.toExprString("[runtime expression]");
1088                            }
1089                            ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF);
1090                    }
1091                    else adapter.push("");
1092                    
1093                    // dspName
1094                    attr = component.removeAttribute("displayname");
1095                    if(attr==null) attr=component.getAttribute("display");
1096                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1097                    else adapter.push("");
1098                                    
1099                    // callpath
1100                    adapter.visitVarInsn(Opcodes.ALOAD, 2);
1101                    // realpath
1102                    adapter.visitVarInsn(Opcodes.ILOAD, 3);
1103                    
1104    
1105                    // style
1106                    attr = component.removeAttribute("style");
1107                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1108                    else adapter.push("");
1109    
1110                    // persistent
1111                    attr = component.removeAttribute("persistent");
1112                    boolean persistent=false;
1113                    if(attr!=null) {
1114                            persistent=ASMUtil.toBoolean(attr,component.getStart()).booleanValue();
1115                    }
1116                    
1117                    // persistent
1118                    attr = component.removeAttribute("accessors");
1119                    boolean accessors=false;
1120                    if(attr!=null) {
1121                            accessors=ASMUtil.toBoolean(attr,component.getStart()).booleanValue();
1122                    }
1123    
1124                    adapter.push(persistent);
1125                    adapter.push(accessors);
1126                    //ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE);
1127                    
1128                    //adapter.visitVarInsn(Opcodes.ALOAD, 4);
1129                    createMetaDataStruct(bc,component.getAttributes(),component.getMetaData());
1130                    
1131                    adapter.invokeConstructor(Types.COMPONENT_IMPL, CONSTR_COMPONENT_IMPL);
1132                    
1133                    adapter.storeLocal(comp);
1134                    
1135                    //Component Impl(ComponentPage componentPage,boolean output, String extend, String hint, String dspName)
1136                    
1137                    
1138                    // initComponent(pc,c);
1139                    adapter.visitVarInsn(Opcodes.ALOAD, 0);
1140                    adapter.loadArg(0);
1141                    adapter.loadLocal(comp);
1142                    adapter.invokeVirtual(Types.COMPONENT_PAGE, INIT_COMPONENT);
1143                    
1144            adapter.visitLabel(methodEnd);
1145            
1146            // return component;
1147            adapter.loadLocal(comp);
1148    
1149            adapter.returnValue();
1150            //ExpressionUtil.visitLine(adapter, component.getEndLine());
1151            adapter.endMethod();
1152                    
1153            
1154            }
1155            
1156            private void writeOutNewInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag interf) throws BytecodeException {
1157                    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_INTERFACE_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
1158            BytecodeContext bc=new BytecodeContext(statConstr, constr,this,externalizer,keys,cw,name,adapter,NEW_INTERFACE_IMPL_INSTANCE,writeLog(),supressWSbeforeArg);
1159            Label methodBegin=new Label();
1160            Label methodEnd=new Label();
1161    
1162            
1163                    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
1164            adapter.visitLabel(methodBegin);
1165    
1166            //ExpressionUtil.visitLine(adapter, interf.getStartLine());
1167            
1168                    int comp=adapter.newLocal(Types.INTERFACE_IMPL);
1169                    
1170                    
1171                    adapter.newInstance(Types.INTERFACE_IMPL);
1172                    adapter.dup();
1173                    
1174                    
1175                    Attribute attr;
1176                    // Interface Page
1177                    adapter.visitVarInsn(Opcodes.ALOAD, 0);
1178                    adapter.checkCast(Types.INTERFACE_PAGE);
1179    
1180                    // extened
1181                    attr = interf.removeAttribute("extends");
1182                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1183                    else adapter.push("");
1184                    
1185                    // hint
1186                    attr = interf.removeAttribute("hint");
1187                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1188                    else adapter.push("");
1189                    
1190                    // dspName
1191                    attr = interf.removeAttribute("displayname");
1192                    if(attr==null) attr=interf.getAttribute("display");
1193                    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
1194                    else adapter.push("");
1195                    
1196                    
1197                    // callpath
1198                    adapter.visitVarInsn(Opcodes.ALOAD, 1);
1199                    // realpath
1200                    adapter.visitVarInsn(Opcodes.ILOAD, 2);
1201                    
1202                    // interface udfs
1203                    adapter.visitVarInsn(Opcodes.ALOAD, 3);
1204                    
1205                    createMetaDataStruct(bc,interf.getAttributes(),interf.getMetaData());
1206                    
1207                    
1208                    adapter.invokeConstructor(Types.INTERFACE_IMPL, CONSTR_INTERFACE_IMPL);
1209                    
1210                    adapter.storeLocal(comp);
1211                    
1212                    
1213                    
1214                    // initInterface(pc,c);
1215                    adapter.visitVarInsn(Opcodes.ALOAD, 0);
1216                    //adapter.loadArg(0);
1217                    adapter.loadLocal(comp);
1218                    adapter.invokeVirtual(Types.INTERFACE_PAGE, INIT_INTERFACE);
1219                    
1220                    adapter.visitLabel(methodEnd);
1221            
1222            
1223            // return interface;
1224            adapter.loadLocal(comp);
1225    
1226            adapter.returnValue();
1227            //ExpressionUtil.visitLine(adapter, interf.getEndLine());
1228            adapter.endMethod();
1229                    
1230            
1231            }
1232            
1233            public static boolean hasMetaDataStruct(Map attrs, Map meta) {
1234                    if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){
1235                            return false;
1236                    }
1237                    return true;
1238            }
1239            
1240            public static void createMetaDataStruct(BytecodeContext bc, Map attrs, Map meta) throws BytecodeException {
1241                    
1242                    
1243                    GeneratorAdapter adapter = bc.getAdapter();
1244                    if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){
1245                            ASMConstants.NULL(bc.getAdapter());
1246                            bc.getAdapter().cast(Types.OBJECT,STRUCT_IMPL);
1247                            return;
1248                    }
1249                    
1250                    int sct=adapter.newLocal(STRUCT_IMPL);
1251                    adapter.newInstance(STRUCT_IMPL);
1252                    adapter.dup();
1253                    adapter.invokeConstructor(STRUCT_IMPL, INIT_STRUCT_IMPL);
1254                    adapter.storeLocal(sct);
1255                    if(meta!=null) {
1256                            _createMetaDataStruct(bc,adapter,sct,meta);
1257                    }
1258                    if(attrs!=null) {
1259                            _createMetaDataStruct(bc,adapter,sct,attrs);
1260                    }
1261                    
1262                    
1263                    adapter.loadLocal(sct);
1264            }
1265    
1266            private static void _createMetaDataStruct(BytecodeContext bc, GeneratorAdapter adapter, int sct, Map attrs) throws BytecodeException {
1267                    Attribute attr;
1268                    Iterator it = attrs.entrySet().iterator();
1269                    Entry entry;
1270                    while(it.hasNext()){
1271                            entry = (Map.Entry)it.next();
1272                            attr=(Attribute) entry.getValue();
1273                            adapter.loadLocal(sct);
1274                            adapter.push(attr.getName());
1275                            if(attr.getValue() instanceof Literal)
1276                                    ExpressionUtil.writeOutSilent(attr.getValue(),bc,Expression.MODE_REF);
1277                            else
1278                                    adapter.push("[runtime expression]");
1279                            
1280                            adapter.invokeVirtual(STRUCT_IMPL, SET_EL);
1281                            adapter.pop();
1282                    }
1283            }
1284    
1285            private void writeOutCall(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw) throws BytecodeException {
1286                    //GeneratorAdapter adapter = bc.getAdapter();
1287                    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , CALL, null, new Type[]{Types.THROWABLE}, cw);
1288                    Label methodBegin=new Label();
1289                    Label methodEnd=new Label();
1290            
1291                            adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
1292                    adapter.visitLabel(methodBegin);
1293    
1294                                    writeOutCallBody(new BytecodeContext(statConstr, constr,this,externalizer,keys,cw,name,adapter,CALL,writeLog(),supressWSbeforeArg),this,IFunction.PAGE_TYPE_REGULAR);
1295                    
1296                    adapter.visitLabel(methodEnd);
1297                    adapter.returnValue();
1298            adapter.endMethod();
1299        }
1300    
1301    
1302            private void writeOutCallBody(BytecodeContext bc,Body body, int pageType) throws BytecodeException {
1303                    // Other
1304                    List<IFunction> functions=new ArrayList<IFunction>();
1305                    getFunctions(functions,bc,body,pageType);
1306                    
1307                    String className = Types.UDF_PROPERTIES_ARRAY.toString();
1308                    //FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE , "udfs",className , null, null);
1309                    //fv.visitEnd();
1310                    
1311                    BytecodeContext constr = bc.getConstructor();
1312                    GeneratorAdapter cga = constr.getAdapter();
1313                    
1314                    cga.visitVarInsn(Opcodes.ALOAD, 0);
1315                    cga.push(functions.size());
1316                    //cga.visitTypeInsn(Opcodes.ANEWARRAY, Types.UDF_PROPERTIES.toString());
1317                    cga.newArray(Types.UDF_PROPERTIES);
1318                    cga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "udfs", className);
1319                    
1320                    
1321                    Iterator<IFunction> it = functions.iterator();
1322                    while(it.hasNext()){
1323                            it.next().writeOut(bc, pageType);
1324                    }
1325                    
1326                    if(pageType==IFunction.PAGE_TYPE_COMPONENT) {
1327                            GeneratorAdapter adapter = bc.getAdapter();
1328                            adapter.loadArg(1);
1329                            adapter.loadArg(0);
1330                            adapter.visitVarInsn(Opcodes.ALOAD, 0);
1331                            adapter.invokeVirtual(Types.COMPONENT_IMPL, CHECK_INTERFACE);
1332    
1333                    }
1334                    if(pageType!=IFunction.PAGE_TYPE_INTERFACE){
1335                            BodyBase.writeOut(bc.getStaticConstructor(),bc.getConstructor(),bc.getKeys(),body.getStatements(), bc);
1336                    }
1337            }
1338    
1339            private static void getImports(List<String> list,Body body) throws BytecodeException {
1340                    if(ASMUtil.isEmpty(body)) return;
1341                    Statement stat;
1342                    List stats = body.getStatements();
1343            int len=stats.size();
1344            for(int i=0;i<len;i++) {
1345                    stat = (Statement)stats.get(i);
1346                    
1347                    // IFunction
1348                    if(stat instanceof TagImport && !StringUtil.isEmpty(((TagImport)stat).getPath(),true)) {
1349                            ImportDefintion id = ImportDefintionImpl.getInstance(((TagImport) stat).getPath(), null);
1350                            if(id!=null && (!list.contains(id.toString()) && !list.contains(id.getPackage()+".*"))){
1351                                    list.add(id.toString());
1352                            }
1353                            stats.remove(i);
1354                            len--;
1355                            i--;
1356                            
1357                    }
1358                    else if(stat instanceof HasBody) getImports(list, ((HasBody)stat).getBody());
1359                    else if(stat instanceof HasBodies) {
1360                            Body[] bodies=((HasBodies)stat).getBodies();
1361                            for(int y=0;y<bodies.length;y++) {
1362                                    getImports(list,bodies[y]);
1363                            }
1364                    }
1365            }
1366            }
1367            
1368            
1369            private static void getFunctions(List<IFunction> functions,BytecodeContext bc, Body body, int pageType) throws BytecodeException {
1370                    //writeOutImports(bc, body, pageType);
1371                    if(ASMUtil.isEmpty(body)) return;
1372                    Statement stat;
1373                    List stats = body.getStatements();
1374            int len=stats.size();
1375            for(int i=0;i<len;i++) {
1376                    stat = (Statement)stats.get(i);
1377                    
1378                    // IFunction
1379                    if(stat instanceof IFunction) {
1380                            functions.add((IFunction)stat);
1381                            //((IFunction)stat).writeOut(bc,pageType);
1382                            stats.remove(i);
1383                            len--;
1384                            i--;
1385                    }
1386                    else if(stat instanceof HasBody) getFunctions(functions,bc, ((HasBody)stat).getBody(), pageType);
1387                    else if(stat instanceof HasBodies) {
1388                            Body[] bodies=((HasBodies)stat).getBodies();
1389                            for(int y=0;y<bodies.length;y++) {
1390                                    getFunctions(functions,bc,bodies[y] , pageType);
1391                            }
1392                            
1393                    }
1394            }
1395            }
1396    
1397    
1398            /**
1399             * @return the source
1400             */
1401            public String getSource() {
1402                    return path;
1403            }
1404    
1405            /**
1406             * @return if it is a component
1407             */
1408            public boolean isComponent() {
1409                    return isComponent;
1410            }
1411            
1412            /**
1413             * set if the page is a component or not
1414             * @param cfc 
1415             */
1416            public void setIsComponent(boolean isComponent) {
1417                    this.isComponent = isComponent;
1418            }
1419    
1420            /**
1421             * @return if it is a component
1422             */
1423            public boolean isInterface() {
1424                    return isInterface;
1425            }
1426            
1427    
1428            public boolean isPage() {
1429                    return !isInterface && !isComponent;
1430            }
1431            
1432            /**
1433             * set if the page is a component or not
1434             * @param cfc 
1435             */
1436            public void setIsInterface(boolean isInterface) {
1437                    this.isInterface = isInterface;
1438            }
1439            /**
1440             * @return the lastModifed
1441             */
1442            public long getLastModifed() {
1443                    return lastModifed;
1444            }
1445    
1446    
1447            public int[] addFunction(IFunction function) {
1448                    int[] indexes=new int[2];
1449                    Iterator<IFunction> it = functions.iterator();
1450                    while(it.hasNext()){
1451                            if(it.next() instanceof FunctionImpl)indexes[IFunction.ARRAY_INDEX]++;
1452                    }
1453                    indexes[IFunction.VALUE_INDEX]=functions.size();
1454                    
1455                    functions.add(function);
1456                    return indexes;
1457            }
1458            
1459            public int addThread(TagThread thread) {
1460                    threads.add(thread);
1461                    return threads.size()-1;
1462            }
1463    
1464            public static byte[] setSourceLastModified(byte[] barr,  long lastModified) {
1465                    ClassReader cr = new ClassReader(barr);
1466                    ClassWriter cw = ASMUtil.getClassWriter();
1467                    ClassVisitor ca = new SourceLastModifiedClassAdapter(cw,lastModified);
1468                    cr.accept(ca, ClassReader.SKIP_DEBUG);
1469                    return cw.toByteArray();
1470            }
1471            
1472    
1473    
1474    }
1475            class SourceLastModifiedClassAdapter extends ClassVisitor {
1476    
1477                    private long lastModified;
1478                    public SourceLastModifiedClassAdapter(ClassWriter cw, long lastModified) {
1479                            super(Opcodes.ASM4,cw);
1480                            this.lastModified=lastModified;
1481                    }
1482                    public MethodVisitor visitMethod(int access,String name, String desc,  String signature, String[] exceptions) {
1483                            
1484                            if(!name.equals("getSourceLastModified"))return super.visitMethod(access,name, desc, signature, exceptions);
1485                            
1486                            MethodVisitor mv = cv.visitMethod(access,name, desc, signature, exceptions);
1487                            mv.visitCode();
1488                            mv.visitLdcInsn(Long.valueOf(lastModified));
1489                            mv.visitInsn(Opcodes.LRETURN);
1490                            mv.visitEnd();
1491                            return mv;
1492                    }
1493    
1494            }