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