001    package railo.transformer.bytecode.util;
002    
003    import java.io.IOException;
004    import java.util.ArrayList;
005    import java.util.Iterator;
006    import java.util.List;
007    
008    import org.objectweb.asm.ClassReader;
009    import org.objectweb.asm.ClassWriter;
010    import org.objectweb.asm.FieldVisitor;
011    import org.objectweb.asm.Label;
012    import org.objectweb.asm.Opcodes;
013    import org.objectweb.asm.Type;
014    import org.objectweb.asm.commons.GeneratorAdapter;
015    import org.objectweb.asm.commons.Method;
016    
017    import railo.aprint;
018    import railo.commons.digest.MD5;
019    import railo.commons.io.IOUtil;
020    import railo.commons.io.res.Resource;
021    import railo.commons.lang.StringUtil;
022    import railo.runtime.component.Property;
023    import railo.runtime.exp.PageException;
024    import railo.runtime.net.rpc.AxisCaster;
025    import railo.runtime.op.Caster;
026    import railo.runtime.type.dt.TimeSpanImpl;
027    import railo.runtime.type.util.ArrayUtil;
028    import railo.runtime.type.util.ListUtil;
029    import railo.transformer.bytecode.Body;
030    import railo.transformer.bytecode.BytecodeContext;
031    import railo.transformer.bytecode.BytecodeException;
032    import railo.transformer.bytecode.Literal;
033    import railo.transformer.bytecode.Page;
034    import railo.transformer.bytecode.Position;
035    import railo.transformer.bytecode.ScriptBody;
036    import railo.transformer.bytecode.Statement;
037    import railo.transformer.bytecode.cast.Cast;
038    import railo.transformer.bytecode.cast.CastBoolean;
039    import railo.transformer.bytecode.cast.CastDouble;
040    import railo.transformer.bytecode.cast.CastString;
041    import railo.transformer.bytecode.expression.ExprDouble;
042    import railo.transformer.bytecode.expression.ExprString;
043    import railo.transformer.bytecode.expression.Expression;
044    import railo.transformer.bytecode.expression.var.Argument;
045    import railo.transformer.bytecode.expression.var.BIF;
046    import railo.transformer.bytecode.expression.var.Member;
047    import railo.transformer.bytecode.expression.var.NullExpression;
048    import railo.transformer.bytecode.expression.var.Variable;
049    import railo.transformer.bytecode.expression.var.VariableString;
050    import railo.transformer.bytecode.literal.Identifier;
051    import railo.transformer.bytecode.literal.LitBoolean;
052    import railo.transformer.bytecode.literal.LitDouble;
053    import railo.transformer.bytecode.literal.LitString;
054    import railo.transformer.bytecode.statement.FlowControl;
055    import railo.transformer.bytecode.statement.FlowControlBreak;
056    import railo.transformer.bytecode.statement.FlowControlContinue;
057    import railo.transformer.bytecode.statement.FlowControlFinal;
058    import railo.transformer.bytecode.statement.FlowControlRetry;
059    import railo.transformer.bytecode.statement.PrintOut;
060    import railo.transformer.bytecode.statement.TryCatchFinally;
061    import railo.transformer.bytecode.statement.tag.Attribute;
062    import railo.transformer.bytecode.statement.tag.Tag;
063    import railo.transformer.bytecode.statement.tag.TagComponent;
064    import railo.transformer.bytecode.statement.tag.TagTry;
065    import railo.transformer.cfml.evaluator.EvaluatorException;
066    
067    public final class ASMUtil {
068    
069            //private static final int VERSION_2=1;
070            //private static final int VERSION_3=2;
071    
072            public static final short TYPE_ALL=0;
073            public static final short TYPE_BOOLEAN=1;
074            public static final short TYPE_NUMERIC=2;
075            public static final short TYPE_STRING=4;
076            
077            
078            
079            
080            //private static int version=0;
081            
082            private final static Method CONSTRUCTOR_OBJECT = Method.getMethod("void <init> ()");
083            private static final Method _SRC_NAME = new Method("_srcName",
084                                    Types.STRING,
085                                    new Type[]{}
086                            );;
087            //private static final String VERSION_MESSAGE = "you use an invalid version of the ASM Jar, please update your jar files";
088            private static long id=0;
089                    
090            /**
091             * Gibt zurueck ob das direkt uebergeordnete Tag mit dem uebergebenen Full-Name (Namespace und Name) existiert.
092             * @param el Startelement, von wo aus gesucht werden soll.
093             * @param fullName Name des gesuchten Tags.
094             * @return Existiert ein solches Tag oder nicht.
095             */
096            public static boolean hasAncestorTag(Tag tag, String fullName) {
097                return getAncestorTag(tag, fullName)!=null;
098            }
099            
100    
101            /**
102             * Gibt das uebergeordnete CFXD Tag Element zurueck, falls dies nicht existiert wird null zurueckgegeben.
103             * @param el Element von dem das parent Element zurueckgegeben werden soll.
104             * @return uebergeordnete CFXD Tag Element
105             */
106            public static Tag getParentTag(Tag tag) {
107                    Statement p=tag.getParent();
108                    if(p==null)return null;
109                    p=p.getParent();
110                    if(p instanceof Tag) return (Tag) p;
111                    return null;
112            }
113    
114            public static boolean isParentTag(Tag tag,String fullName)      {
115                    Tag p = getParentTag(tag);
116                    if(p==null) return false;
117                    return p.getFullname().equalsIgnoreCase(fullName);
118                    
119            }
120            public static boolean isParentTag(Tag tag,Class clazz)  {
121                    Tag p = getParentTag(tag);
122                    if(p==null) return false;
123                    return p.getClass()==clazz;
124                    
125            }
126            
127            public static boolean hasAncestorRetryFCStatement(Statement stat,String label) {
128                    return getAncestorRetryFCStatement(stat,null,label)!=null;
129            }
130            
131            public static boolean hasAncestorBreakFCStatement(Statement stat,String label) {
132                    return getAncestorBreakFCStatement(stat,null,label)!=null;
133            }
134            
135            public static boolean hasAncestorContinueFCStatement(Statement stat,String label) {
136                    return getAncestorContinueFCStatement(stat,null,label)!=null;
137            }
138            
139            
140            
141            public static FlowControlRetry getAncestorRetryFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) {
142                    return (FlowControlRetry) getAncestorFCStatement(stat, finallyLabels, FlowControl.RETRY,label);
143            }
144            public static FlowControlBreak getAncestorBreakFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) {
145                    return (FlowControlBreak) getAncestorFCStatement(stat, finallyLabels, FlowControl.BREAK,label);
146            }
147            
148            public static FlowControlContinue getAncestorContinueFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) {
149                    return (FlowControlContinue) getAncestorFCStatement(stat, finallyLabels, FlowControl.CONTINUE,label);
150            }
151    
152            private static FlowControl getAncestorFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, int flowType, String label) {
153                    Statement parent = stat;
154                    FlowControlFinal fcf;
155                    while(true)     {
156                            parent=parent.getParent();
157                            if(parent==null)return null;
158                            if(
159                               ((flowType==FlowControl.RETRY && parent instanceof FlowControlRetry) || 
160                               (flowType==FlowControl.CONTINUE && parent instanceof FlowControlContinue) || 
161                               (flowType==FlowControl.BREAK && parent instanceof FlowControlBreak))
162                               &&
163                                    labelMatch((FlowControl)parent,label))  {
164                                    if(parent instanceof ScriptBody){
165                                            List<FlowControlFinal> _finallyLabels=finallyLabels==null?null:new ArrayList<FlowControlFinal>();
166                                            
167                                            FlowControl scriptBodyParent = getAncestorFCStatement(parent,_finallyLabels,flowType,label);
168                                            if(scriptBodyParent!=null) {
169                                                    if(finallyLabels!=null){
170                                                            Iterator<FlowControlFinal> it = _finallyLabels.iterator();
171                                                            while(it.hasNext()){
172                                                                    finallyLabels.add(it.next());
173                                                            }
174                                                    }
175                                                    return scriptBodyParent;
176                                            }
177                                            return (FlowControl)parent;
178                                    }
179                                    return (FlowControl) parent;
180                            }
181                            
182                            // only if not last
183                            if(finallyLabels!=null){
184                                    fcf = parent.getFlowControlFinal();
185                                    if(fcf!=null){
186                                            finallyLabels.add(fcf);
187                                    }
188                            }
189                            
190                    }
191            }
192            
193            private static boolean labelMatch(FlowControl fc, String label) {
194                    if(StringUtil.isEmpty(label,true)) return true;
195                    String fcl = fc.getLabel();
196                    if(StringUtil.isEmpty(fcl,true)) return false;
197                    
198                    return label.trim().equalsIgnoreCase(fcl.trim());
199            }
200    
201    
202            public static void leadFlow(BytecodeContext bc,Statement stat, int flowType, String label) throws BytecodeException {
203                    List<FlowControlFinal> finallyLabels=new ArrayList<FlowControlFinal>();
204                    
205                    FlowControl fc;
206                    String name;
207                    if(FlowControl.BREAK==flowType) {
208                            fc=ASMUtil.getAncestorBreakFCStatement(stat,finallyLabels,label);
209                            name="break";
210                    }
211                    else if(FlowControl.CONTINUE==flowType) {
212                            fc=ASMUtil.getAncestorContinueFCStatement(stat,finallyLabels,label);
213                            name="continue";
214                    }
215                    else  {
216                            fc=ASMUtil.getAncestorRetryFCStatement(stat,finallyLabels,label);
217                            name="retry";
218                    }
219                    
220                    if(fc==null)
221                            throw new BytecodeException(name+" must be inside a loop (for,while,do-while,<cfloop>,<cfwhile> ...)",stat.getStart());
222                    
223                    GeneratorAdapter adapter = bc.getAdapter();
224                    
225                    Label end;
226                    if(FlowControl.BREAK==flowType) end=((FlowControlBreak)fc).getBreakLabel();
227                    else if(FlowControl.CONTINUE==flowType) end=((FlowControlContinue)fc).getContinueLabel();
228                    else  end=((FlowControlRetry)fc).getRetryLabel();
229    
230                    // first jump to all final labels
231                    FlowControlFinal[] arr = finallyLabels.toArray(new FlowControlFinal[finallyLabels.size()]);
232                    if(arr.length>0) {
233                            FlowControlFinal fcf;
234                            for(int i=0;i<arr.length;i++){
235                                    fcf=arr[i];
236                                    
237                                    // first
238                                    if(i==0) {
239                                            adapter.visitJumpInsn(Opcodes.GOTO, fcf.getFinalEntryLabel());
240                                    }
241                                    
242                                    // last
243                                    if(arr.length==i+1) fcf.setAfterFinalGOTOLabel(end);
244                                    else fcf.setAfterFinalGOTOLabel(arr[i+1].getFinalEntryLabel());
245                            }
246                            
247                    }
248                    else bc.getAdapter().visitJumpInsn(Opcodes.GOTO, end);
249            }
250            
251            
252            
253            public static boolean hasAncestorTryStatement(Statement stat) {
254                    return getAncestorTryStatement(stat)!=null;
255            }
256            
257            public static Statement getAncestorTryStatement(Statement stat) {
258                    Statement parent = stat;
259                    while(true)     {
260                            parent=parent.getParent();
261                            if(parent==null)return null;
262                            
263                            if(parent instanceof TagTry)    {
264                                    return parent;
265                            }
266                            else if(parent instanceof TryCatchFinally)      {
267                                    return parent;
268                            }
269                    }
270            }
271            
272    
273    
274            
275            /**
276             * Gibt ein uebergeordnetes Tag mit dem uebergebenen Full-Name (Namespace und Name) zurueck, 
277             * falls ein solches existiert, andernfalls wird null zurueckgegeben.
278             * @param el Startelement, von wo aus gesucht werden soll.
279             * @param fullName Name des gesuchten Tags.
280             * @return  �bergeornetes Element oder null.
281             */
282            public static Tag getAncestorTag(Tag tag, String fullName) {
283                    Statement parent=tag;
284                    while(true)     {
285                            parent=parent.getParent();
286                            if(parent==null)return null;
287                            if(parent instanceof Tag)       {
288                                    tag=(Tag) parent;
289                                    if(tag.getFullname().equalsIgnoreCase(fullName))
290                                            return tag;
291                            }
292                    }
293            }
294            
295            
296    
297        /**
298         * extract the content of a attribut
299         * @param cfxdTag
300         * @param attrName
301         * @return attribute value
302         * @throws EvaluatorException
303         */
304            public static Boolean getAttributeBoolean(Tag tag,String attrName) throws EvaluatorException {
305                    Boolean b= getAttributeLiteral(tag, attrName).getBoolean(null);
306                    if(b==null)throw new EvaluatorException("attribute ["+attrName+"] must be a constant boolean value");
307                    return b;
308        }
309        
310        /**
311         * extract the content of a attribut
312         * @param cfxdTag
313         * @param attrName
314         * @return attribute value
315         * @throws EvaluatorException
316         */
317            public static Boolean getAttributeBoolean(Tag tag,String attrName, Boolean defaultValue) {
318                    Literal lit=getAttributeLiteral(tag, attrName,null);
319                    if(lit==null) return defaultValue;
320                    return lit.getBoolean(defaultValue); 
321        }
322    
323    
324        /**
325         * extract the content of a attribut
326         * @param cfxdTag
327         * @param attrName
328         * @return attribute value
329         * @throws EvaluatorException
330         */
331            public static String getAttributeString(Tag tag,String attrName) throws EvaluatorException {
332                    return getAttributeLiteral(tag, attrName).getString();
333        }
334        
335        /**
336         * extract the content of a attribut
337         * @param cfxdTag
338         * @param attrName
339         * @return attribute value
340         * @throws EvaluatorException
341         */
342            public static String getAttributeString(Tag tag,String attrName, String defaultValue) {
343                    Literal lit=getAttributeLiteral(tag, attrName,null);
344                    if(lit==null) return defaultValue;
345                    return lit.getString(); 
346        }
347            
348            /**
349         * extract the content of a attribut
350         * @param cfxdTag
351         * @param attrName
352         * @return attribute value
353         * @throws EvaluatorException
354         */
355            public static Literal getAttributeLiteral(Tag tag,String attrName) throws EvaluatorException {
356                    Attribute attr = tag.getAttribute(attrName);
357                    if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue());
358            throw new EvaluatorException("attribute ["+attrName+"] must be a constant value");
359        }
360            
361            
362        
363        /**
364         * extract the content of a attribut
365         * @param cfxdTag
366         * @param attrName
367         * @return attribute value
368         * @throws EvaluatorException
369         */
370            public static Literal getAttributeLiteral(Tag tag,String attrName, Literal defaultValue) {
371                    Attribute attr = tag.getAttribute(attrName);
372                    if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue());
373            return defaultValue; 
374        }
375            
376            
377            
378    
379            /**
380             * Prueft ob das das angegebene Tag in der gleichen Ebene nach dem angegebenen Tag vorkommt.
381             * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen.
382             * @param nameToFind Tag Name der nicht vorkommen darf
383             * @return kommt das Tag vor.
384             */
385            public static boolean hasSisterTagAfter(Tag tag, String nameToFind) {
386                    Body body=(Body) tag.getParent();
387                    List<Statement> stats = body.getStatements();
388                    Iterator<Statement> it = stats.iterator();
389                    Statement other;
390                    
391                    boolean isAfter=false;
392                    while(it.hasNext()) {
393                            other=it.next();
394                            
395                            if(other instanceof Tag) {
396                                    if(isAfter) {
397                                            if(((Tag) other).getTagLibTag().getName().equals(nameToFind))
398                                            return true;
399                                    }
400                                    else if(other == tag) isAfter=true;
401                            }
402                    }
403                    return false;
404            }
405            
406            /**
407             * Prueft ob das angegebene Tag innerhalb seiner Ebene einmalig ist oder nicht.
408             * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen.
409             * @return kommt das Tag vor.
410             */
411            public static boolean hasSisterTagWithSameName(Tag tag) {
412                    
413                    Body body=(Body) tag.getParent();
414                    List<Statement> stats = body.getStatements();
415                    Iterator<Statement> it = stats.iterator();
416                    Statement other;
417                    String name=tag.getTagLibTag().getName();
418                    
419                    while(it.hasNext()) {
420                            other=it.next();
421                            if(other != tag && other instanceof Tag && ((Tag) other).getTagLibTag().getName().equals(name))
422                                            return true;
423                            
424                    }
425                    return false;
426            }
427    
428            /**
429             * remove this tag from his parent body
430             * @param tag
431             */
432            public static void remove(Tag tag) {
433                    Body body=(Body) tag.getParent();
434                    body.getStatements().remove(tag);
435            }
436    
437            /**
438             * replace src with trg
439             * @param src
440             * @param trg
441             */
442            public static void replace(Tag src, Tag trg, boolean moveBody) {
443                    trg.setParent(src.getParent());
444                    
445                    Body p=(Body) src.getParent();
446                    List<Statement> stats = p.getStatements();
447                    Iterator<Statement> it = stats.iterator();
448                    Statement stat;
449                    int count=0;
450                    
451                    while(it.hasNext()) {
452                            stat=it.next();
453                            if(stat==src) {
454                                    if(moveBody && src.getBody()!=null)src.getBody().setParent(trg);
455                                    stats.set(count, trg);
456                                    break;
457                            }
458                            count++;
459                    }
460            }
461            
462            public static Page getAncestorPage(Statement stat) throws BytecodeException {
463                    Statement parent=stat;
464                    while(true)     {
465                            parent=parent.getParent();
466                            if(parent==null) {
467                                    throw new BytecodeException("missing parent Statement of Statement",stat.getStart());
468                                    //return null;
469                            }
470                            if(parent instanceof Page)      return (Page) parent;
471                    }
472            }
473            
474            public static Page getAncestorPage(Statement stat, Page defaultValue) {
475                    Statement parent=stat;
476                    while(true)     {
477                            parent=parent.getParent();
478                            if(parent==null) {
479                                    return defaultValue;
480                            }
481                            if(parent instanceof Page)      return (Page) parent;
482                    }
483            }
484            
485            public static void listAncestor(Statement stat) {
486                    Statement parent=stat;
487                    aprint.o(stat);
488                    while(true)     {
489                            parent=parent.getParent();
490                            if(parent instanceof Page)aprint.o("page-> "+ ((Page)parent).getSource());
491                            else aprint.o("parent-> "+ parent);
492                            if(parent==null) break;
493                    }
494            }
495            
496            
497            public static Tag getAncestorComponent(Statement stat) throws BytecodeException {
498                    //print.ln("getAncestorPage:"+stat);
499                    Statement parent=stat;
500                    while(true)     {
501                            parent=parent.getParent();
502                            //print.ln(" - "+parent);
503                            if(parent==null) {
504                                    throw new BytecodeException("missing parent Statement of Statement",stat.getStart());
505                                    //return null;
506                            }
507                            if(parent instanceof TagComponent)
508                            //if(parent instanceof Tag && "component".equals(((Tag)parent).getTagLibTag().getName()))       
509                                    return (Tag) parent;
510                    }
511            }
512            
513            public static Statement getRoot(Statement stat) {
514                    while(true)     {
515                            if(isRoot(stat))        {
516                                    return stat;
517                            }
518                            stat=stat.getParent();
519                    }
520            }
521    
522    
523    
524        public static boolean isRoot(Statement statement) { 
525            //return statement instanceof Page || (statement instanceof Tag && "component".equals(((Tag)statement).getTagLibTag().getName()));
526            return statement instanceof Page || statement instanceof TagComponent;
527        }
528            
529            public static void invokeMethod(GeneratorAdapter adapter, Type type, Method method) {
530                    if(type.getClass().isInterface())
531                            adapter.invokeInterface(type, method);
532                    else
533                            adapter.invokeVirtual(type, method);
534            }
535    
536        public static byte[] createPojo(String className, ASMProperty[] properties,Class parent,Class[] interfaces, String srcName) throws PageException {
537            className=className.replace('.', '/');
538            className=className.replace('\\', '/');
539            className=ListUtil.trim(className, "/");
540            String[] inter=null;
541            if(interfaces!=null){
542                    inter=new String[interfaces.length];
543                    for(int i=0;i<inter.length;i++){
544                            inter[i]=interfaces[i].getName().replace('.', '/');
545                    }
546            }
547        // CREATE CLASS     
548                    //ClassWriter cw = new ClassWriter(true);
549            ClassWriter cw = ASMUtil.getClassWriter();
550            cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC, className, null, parent.getName().replace('.', '/'), inter);
551            String md5;
552            try{
553                    md5=createMD5(properties);
554            }
555            catch(Throwable t){
556                    md5="";
557                    t.printStackTrace();
558            }
559            
560            FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "_md5_", "Ljava/lang/String;", null, md5);
561            fv.visitEnd();
562            
563            
564        // Constructor
565            GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_OBJECT,null,null,cw);
566            adapter.loadThis();
567            adapter.invokeConstructor(toType(parent,true), CONSTRUCTOR_OBJECT);
568            adapter.returnValue();
569            adapter.endMethod();
570        
571            // properties
572            for(int i=0;i<properties.length;i++){
573                    createProperty(cw,className,properties[i]);
574            }
575            
576            // complexType src
577            if(!StringUtil.isEmpty(srcName)) {
578                    GeneratorAdapter _adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+ Opcodes.ACC_STATIC , _SRC_NAME, null, null, cw);
579                    _adapter.push(srcName);
580                    _adapter.returnValue();
581                    _adapter.endMethod();
582            }
583            
584            cw.visitEnd();
585            return cw.toByteArray();
586        }
587        
588        private static void createProperty(ClassWriter cw,String classType, ASMProperty property) throws PageException {
589                    String name = property.getName();
590                    Type type = property.getASMType();
591                    Class clazz = property.getClazz();
592                    
593                    cw.visitField(Opcodes.ACC_PRIVATE, name, type.toString(), null, null).visitEnd();
594                    
595                    int load=loadFor(type);
596                    //int sizeOf=sizeOf(type);
597                    
598            // get<PropertyName>():<type>
599                    Type[] types=new Type[0];
600                    Method method = new Method((clazz==boolean.class?"get":"get")+StringUtil.ucFirst(name),type,types);
601                GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw);
602                
603                Label start = new Label();
604                adapter.visitLabel(start);
605                
606                adapter.visitVarInsn(Opcodes.ALOAD, 0);
607                            adapter.visitFieldInsn(Opcodes.GETFIELD, classType, name, type.toString());
608                            adapter.returnValue();
609                            
610                            Label end = new Label();
611                            adapter.visitLabel(end);
612                            adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0);
613                            adapter.visitEnd();
614                            
615                            adapter.endMethod();
616                            
617                            
618                            
619                            
620                    
621                    // set<PropertyName>(object):void
622                            types=new Type[]{type};
623                            method = new Method("set"+StringUtil.ucFirst(name),Types.VOID,types);
624                adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw);
625                
626                start = new Label();
627                adapter.visitLabel(start);
628                adapter.visitVarInsn(Opcodes.ALOAD, 0);
629                adapter.visitVarInsn(load, 1);
630                adapter.visitFieldInsn(Opcodes.PUTFIELD, classType, name, type.toString());
631                            
632                            adapter.visitInsn(Opcodes.RETURN);
633                            end = new Label();
634                            adapter.visitLabel(end);
635                            adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0);
636                            adapter.visitLocalVariable(name, type.toString(), null, start, end, 1);
637                            //adapter.visitMaxs(0, 0);//.visitMaxs(sizeOf+1, sizeOf+1);// hansx
638                            adapter.visitEnd();
639            
640                            adapter.endMethod();
641                            
642                            
643                            
644                            
645            }
646    
647        public static int loadFor(Type type) {
648            if(type.equals(Types.BOOLEAN_VALUE) || type.equals(Types.INT_VALUE) || type.equals(Types.CHAR) || type.equals(Types.SHORT_VALUE))
649                    return Opcodes.ILOAD;
650            if(type.equals(Types.FLOAT_VALUE))
651                    return Opcodes.FLOAD;
652            if(type.equals(Types.LONG_VALUE))
653                    return Opcodes.LLOAD;
654            if(type.equals(Types.DOUBLE_VALUE))
655                    return Opcodes.DLOAD;
656            return Opcodes.ALOAD;
657            }
658    
659        public static int sizeOf(Type type) {
660            if(type.equals(Types.LONG_VALUE) || type.equals(Types.DOUBLE_VALUE))
661                    return 2;
662            return 1;
663            }
664    
665    
666            /**
667         * translate a string cfml type definition to a Type Object
668         * @param cfType
669         * @param axistype
670         * @return
671         * @throws PageException
672         */
673        public static Type toType(String cfType, boolean axistype) throws PageException {
674                    return toType(Caster.cfTypeToClass(cfType), axistype);
675            }
676    
677        /**
678         * translate a string cfml type definition to a Type Object
679         * @param cfType
680         * @param axistype
681         * @return
682         * @throws PageException
683         */
684        public static Type toType(Class type, boolean axistype) {
685                    if(axistype)type=AxisCaster.toAxisTypeClass(type);
686                    return Type.getType(type);      
687            }
688        
689    
690            public static String createMD5(ASMProperty[] props) {
691                    
692                    StringBuffer sb=new StringBuffer();
693                    for(int i=0;i<props.length;i++){
694                            sb.append("name:"+props[i].getName()+";");
695                            if(props[i] instanceof Property){
696                                    sb.append("type:"+((Property)props[i]).getType()+";");
697                            }
698                            else {
699                                    try {
700                                            sb.append("type:"+props[i].getASMType()+";");
701                                            
702                                    } 
703                                    catch (PageException e) {}
704                            }
705                    }
706                    try {
707                            return MD5.getDigestAsString(sb.toString());
708                    } catch (IOException e) {
709                            return "";
710                    }
711            }
712    
713    
714    
715            public static void removeLiterlChildren(Tag tag, boolean recursive) {
716                    Body body=tag.getBody();
717                    if(body!=null) {
718                    List<Statement> list = body.getStatements();
719                    Statement[] stats = list.toArray(new Statement[list.size()]);
720                    PrintOut po;
721                    Tag t;
722                    for(int i=0;i<stats.length;i++) {
723                    if(stats[i] instanceof PrintOut) {
724                            po=(PrintOut) stats[i];
725                            if(po.getExpr() instanceof Literal) {
726                                    body.getStatements().remove(po);
727                            }
728                    }
729                    else if(recursive && stats[i] instanceof Tag) {
730                            t=(Tag) stats[i];
731                            if(t.getTagLibTag().isAllowRemovingLiteral()) {
732                                    removeLiterlChildren(t, recursive);
733                            }
734                    }
735                }
736            }
737            }
738    
739    
740            public synchronized static String getId() {
741                    if(id<0)id=0;
742                    return StringUtil.addZeros(++id,6);
743            }
744    
745    
746            public static boolean isEmpty(Body body) {
747                    return body==null || body.isEmpty();
748            }
749    
750    
751            /**
752             * @param adapter
753             * @param expr
754             * @param mode
755             */
756            public static void pop(GeneratorAdapter adapter, Expression expr,int mode) {
757                    if(mode==Expression.MODE_VALUE && (expr instanceof ExprDouble))adapter.pop2();
758                    else adapter.pop();
759            }
760            public static void pop(GeneratorAdapter adapter, Type type) {
761                    if(type.equals(Types.DOUBLE_VALUE))adapter.pop2();
762                    else if(type.equals(Types.VOID));
763                    else adapter.pop();
764            }
765    
766    
767            public static ClassWriter getClassWriter() {
768                    return new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES);
769                    /*if(true) return new ClassWriter(ClassWriter.COMPUTE_MAXS);
770                    
771                    
772                    if(version==VERSION_2)
773                            return new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES);
774                    
775                    try{
776                            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
777                            version=VERSION_2;
778                            return cw;
779                    }
780                    catch(NoSuchMethodError err){
781                            if(version==0){
782                                    version=VERSION_3;
783                            }
784                            
785                            PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter();
786                            SystemOut.printDate(ew, VERSION_MESSAGE);
787                            
788                            try {
789                                    return  ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE});
790                                    
791                            } 
792                            catch (Exception e) {
793                                    throw new RuntimeException(Caster.toPageException(e));
794                                    
795                            }
796                    }*/
797            }
798    
799            /*
800             * For 3.1
801             * 
802             * public static ClassWriter getClassWriter() {
803                    if(version==VERSION_3)
804                            return new ClassWriter(ClassWriter.COMPUTE_MAXS);
805                    
806                    try{
807                            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
808                            version=VERSION_3;
809                            return cw;
810                    }
811                    catch(NoSuchMethodError err){
812                            if(version==0){
813                                    version=VERSION_2;
814                                    throw new RuntimeException(new ApplicationException(VERSION_MESSAGE+
815                                                    ", after reload this version will work as well, but please update to newer version"));
816                            }
817                            
818                            PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter();
819                            SystemOut.printDate(ew, VERSION_MESSAGE);
820                            //err.printStackTrace(ew);
821                            
822                            try {
823                                    return (ClassWriter) ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE});
824                                    
825                            } 
826                            catch (Exception e) {
827                                    throw new RuntimeException(Caster.toPageException(e));
828                                    
829                            }
830                    }
831            }*/
832    
833    
834            public static String createOverfowMethod() {
835                    return "_call"+ASMUtil.getId();
836            }
837            
838            public static boolean isOverfowMethod(String name) {
839                    return name.startsWith("_call") && name.length()>=11;
840            }
841    
842    
843            public static boolean isDotKey(ExprString expr) {
844                    return expr instanceof LitString && !((LitString)expr).fromBracket();
845            }
846    
847            public static String toString(Expression exp,String defaultValue) {
848                    try {
849                            return toString(exp);
850                    } catch (BytecodeException e) {
851                            return defaultValue;
852                    }
853            }
854            public static String toString(Expression exp) throws BytecodeException {
855                    if(exp instanceof Variable) {
856                            return toString(VariableString.toExprString(exp));
857                    }
858                    else if(exp instanceof VariableString) {
859                            return ((VariableString)exp).castToString();
860                    }
861                    else if(exp instanceof Literal) {
862                            return ((Literal)exp).toString();
863                    }
864                    return null;
865            }
866    
867    
868            public static Boolean toBoolean(Attribute attr, Position start) throws BytecodeException {
869                    if(attr==null)
870                            throw new BytecodeException("attribute does not exist",start);
871                    
872                    if(attr.getValue() instanceof Literal){
873                            Boolean b=((Literal)attr.getValue()).getBoolean(null);
874                            if(b!=null) return b; 
875                    }
876                    throw new BytecodeException("attribute ["+attr.getName()+"] must be a constant boolean value",start);
877                    
878                    
879            }
880            public static Boolean toBoolean(Attribute attr, int line, Boolean defaultValue) {
881                    if(attr==null)
882                            return defaultValue;
883                    
884                    if(attr.getValue() instanceof Literal){
885                            Boolean b=((Literal)attr.getValue()).getBoolean(null);
886                            if(b!=null) return b; 
887                    }
888                    return defaultValue;    
889            }
890    
891    
892            public static boolean isCFC(Statement s) {
893                    Statement p;
894                    while((p=s.getParent())!=null){
895                            s=p;
896                    }
897                    
898                    return true;
899            }
900    
901            public static boolean isLiteralAttribute(Tag tag, String attrName, short type,boolean required,boolean throwWhenNot) throws EvaluatorException {
902                    return isLiteralAttribute(tag,tag.getAttribute(attrName), type, required, throwWhenNot);
903            }
904            
905            
906            public static boolean isLiteralAttribute(Tag tag,Attribute attr, short type,boolean required,boolean throwWhenNot) throws EvaluatorException {
907                    String strType="/constant";
908                    if(attr!=null && !isNull(attr.getValue())) {
909                            
910                            switch(type){
911                            case TYPE_ALL:
912                                    if(attr.getValue() instanceof Literal) return true;
913                            break;
914                            case TYPE_BOOLEAN:
915                                    if(CastBoolean.toExprBoolean(attr.getValue()) instanceof LitBoolean) return true;
916                                    strType=" boolean";
917                            break;
918                            case TYPE_NUMERIC:
919                                    if(CastDouble.toExprDouble(attr.getValue()) instanceof LitDouble) return true;
920                                    strType=" numeric";
921                            break;
922                            case TYPE_STRING:
923                                    if(CastString.toExprString(attr.getValue()) instanceof LitString) return true;
924                                    strType=" string";
925                            break;
926                            }
927                            if(!throwWhenNot) return false;
928                            throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] must be a literal"+strType+" value. "+
929                                            "attributes java class type "+attr.getValue().getClass().getName());
930                    }
931                    if(required){
932                            if(!throwWhenNot) return false;
933                            throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] is required");
934                    }
935                    return false;
936            }
937    
938    
939            public static boolean isNull(Expression expr) {
940                    if(expr instanceof NullExpression) return true;
941                    if(expr instanceof Cast) {
942                            return isNull(((Cast)expr).getExpr());
943                    }
944                    return false;
945            }
946    
947    
948            public static boolean isRefType(Type type) {
949                    return 
950                    !(type==Types.BYTE_VALUE || type==Types.BOOLEAN_VALUE || type==Types.CHAR || type==Types.DOUBLE_VALUE || 
951                    type==Types.FLOAT_VALUE || type==Types.INT_VALUE || type==Types.LONG_VALUE || type==Types.SHORT_VALUE);
952            }
953    
954    
955            public static Type toRefType(Type type) {
956                    if(type==Types.BYTE_VALUE) return Types.BYTE;
957                    if(type==Types.BOOLEAN_VALUE) return Types.BOOLEAN;
958                    if(type==Types.CHAR) return Types.CHARACTER;
959                    if(type==Types.DOUBLE_VALUE) return Types.DOUBLE;
960                    if(type==Types.FLOAT_VALUE) return Types.FLOAT;
961                    if(type==Types.INT_VALUE) return Types.INTEGER;
962                    if(type==Types.LONG_VALUE) return Types.LONG;
963                    if(type==Types.SHORT_VALUE) return Types.SHORT;
964                    
965                    return type;
966            }
967            
968            /**
969             * return value type only when there is one
970             * @param type
971             * @return
972             */
973            public static Type toValueType(Type type) {
974                    if(type==Types.BYTE) return Types.BYTE_VALUE;
975                    if(type==Types.BOOLEAN) return Types.BOOLEAN_VALUE;
976                    if(type==Types.CHARACTER) return Types.CHAR;
977                    if(type==Types.DOUBLE) return Types.DOUBLE_VALUE;
978                    if(type==Types.FLOAT) return Types.FLOAT_VALUE;
979                    if(type==Types.INTEGER) return Types.INT_VALUE;
980                    if(type==Types.LONG) return Types.LONG_VALUE;
981                    if(type==Types.SHORT) return Types.SHORT_VALUE;
982                    
983                    return type;
984            }
985    
986    
987            public static Class getValueTypeClass(Type type, Class defaultValue) {
988    
989                    if(type==Types.BYTE_VALUE) return byte.class;
990                    if(type==Types.BOOLEAN_VALUE) return boolean.class;
991                    if(type==Types.CHAR) return char.class;
992                    if(type==Types.DOUBLE_VALUE) return double.class;
993                    if(type==Types.FLOAT_VALUE) return float.class;
994                    if(type==Types.INT_VALUE) return int.class;
995                    if(type==Types.LONG_VALUE) return long.class;
996                    if(type==Types.SHORT_VALUE) return short.class;
997                    
998                    return defaultValue;
999            }
1000    
1001    
1002            public static ASMProperty[] toASMProperties(Property[] properties) {
1003                    ASMProperty[] asmp=new ASMProperty[properties.length];
1004                    for(int i=0;i<asmp.length;i++){
1005                            asmp[i]=(ASMProperty) properties[i];
1006                    }
1007                    return asmp;
1008            }
1009            
1010    
1011            public static boolean containsComponent(Body body) {
1012                    if(body==null) return false;
1013                    
1014                    Iterator<Statement> it = body.getStatements().iterator();
1015                    while(it.hasNext()){
1016                            if(it.next() instanceof TagComponent)return true;
1017                    }
1018                    return false;
1019            }
1020    
1021    
1022            public static void dummy1(BytecodeContext bc) {
1023                    bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J");
1024                    bc.getAdapter().visitInsn(Opcodes.POP2);
1025            }
1026            public static void dummy2(BytecodeContext bc) {
1027                    bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "nanoTime", "()J");
1028                    bc.getAdapter().visitInsn(Opcodes.POP2);
1029            }
1030    
1031    
1032            /**
1033             * convert a clas array to a type array
1034             * @param classes
1035             * @return
1036             */
1037            public static Type[] toTypes(Class<?>[] classes) {
1038                    if(classes==null || classes.length==0) 
1039                            return new Type[0];
1040                    
1041                    Type[] types=new Type[classes.length];
1042                    for(int i=0;i<classes.length;i++)    {
1043                            types[i]=Type.getType(classes[i]);
1044                    }
1045                    return types;
1046            }
1047    
1048    
1049            public static String display(ExprString name) {
1050                    if(name instanceof Literal) {
1051                            if(name instanceof Identifier) 
1052                                    return ((Identifier)name).getRaw();
1053                            return ((Literal)name).getString();
1054                            
1055                    }
1056                    return name.toString();
1057            }
1058    
1059    
1060            public static long timeSpanToLong(Expression val) throws EvaluatorException {
1061                    if(val instanceof Literal) {
1062                            Double d = ((Literal)val).getDouble(null);
1063                            if(d==null) throw cacheWithinException();
1064                            return TimeSpanImpl.fromDays(d.doubleValue()).getMillis();
1065                    }
1066                    // createTimespan
1067                    else if(val instanceof Variable) {
1068                            Variable var=(Variable)val;
1069                            if(var.getMembers().size()==1) {
1070                                    Member first = var.getFirstMember();
1071                                    if(first instanceof BIF) {
1072                                            BIF bif=(BIF) first;
1073                                            if("createTimeSpan".equalsIgnoreCase(bif.getFlf().getName())) {
1074                                                    Argument[] args = bif.getArguments();
1075                                                    int len=ArrayUtil.size(args);
1076                                                    if(len>=4 && len<=5) {
1077                                                            double days=toDouble(args[0].getValue());
1078                                                            double hours=toDouble(args[1].getValue());
1079                                                            double minutes=toDouble(args[2].getValue());
1080                                                            double seconds=toDouble(args[3].getValue());
1081                                                            double millis=len==5?toDouble(args[4].getValue()):0;
1082                                                            return new TimeSpanImpl((int)days,(int)hours,(int)minutes,(int)seconds,(int)millis).getMillis();
1083                                                    }
1084                                            }
1085                                    }
1086                            }
1087                    }
1088                    throw cacheWithinException();
1089            }
1090    
1091    
1092    
1093            private static EvaluatorException cacheWithinException() {
1094                    return new EvaluatorException("value of cachedWithin must be a literal timespan, like 0.1 or createTimespan(1,2,3,4)");
1095            }
1096    
1097    
1098            private static double toDouble(Expression e) throws EvaluatorException {
1099                    if(!(e instanceof Literal)) 
1100                            throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context");
1101                    Double d = ((Literal)e).getDouble(null);
1102                    if(d==null)
1103                            throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context");
1104                    
1105                    return d.doubleValue();
1106            }
1107    
1108            public static void visitLabel(GeneratorAdapter ga, Label label) {
1109                    if(label!=null) ga.visitLabel(label);
1110            }
1111            
1112    
1113            
1114            public static String getClassName(Resource res) throws IOException{
1115                    byte[] src=IOUtil.toBytes(res);
1116                    ClassReader cr = new ClassReader(src);
1117                    return cr.getClassName();
1118            }
1119            
1120            public static String getClassName(byte[] barr){
1121                    return new ClassReader(barr).getClassName();
1122            }
1123    
1124    
1125            public static String getSourceName(Class clazz) throws IOException {
1126                    return SourceNameClassVisitor.getSourceName(clazz);
1127            }
1128            
1129    }