Package railo.transformer.bytecode.util

Source Code of railo.transformer.bytecode.util.ASMUtil

package railo.transformer.bytecode.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

import railo.aprint;
import railo.commons.digest.MD5;
import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.commons.lang.StringUtil;
import railo.runtime.component.Property;
import railo.runtime.exp.PageException;
import railo.runtime.net.rpc.AxisCaster;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.type.dt.TimeSpanImpl;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.ListUtil;
import railo.transformer.bytecode.Body;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Literal;
import railo.transformer.bytecode.Page;
import railo.transformer.bytecode.Position;
import railo.transformer.bytecode.ScriptBody;
import railo.transformer.bytecode.Statement;
import railo.transformer.bytecode.cast.Cast;
import railo.transformer.bytecode.cast.CastBoolean;
import railo.transformer.bytecode.cast.CastDouble;
import railo.transformer.bytecode.cast.CastString;
import railo.transformer.bytecode.expression.ExprDouble;
import railo.transformer.bytecode.expression.ExprString;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.expression.var.Argument;
import railo.transformer.bytecode.expression.var.BIF;
import railo.transformer.bytecode.expression.var.DataMember;
import railo.transformer.bytecode.expression.var.Member;
import railo.transformer.bytecode.expression.var.NullExpression;
import railo.transformer.bytecode.expression.var.Variable;
import railo.transformer.bytecode.expression.var.VariableString;
import railo.transformer.bytecode.literal.Identifier;
import railo.transformer.bytecode.literal.LitBoolean;
import railo.transformer.bytecode.literal.LitDouble;
import railo.transformer.bytecode.literal.LitString;
import railo.transformer.bytecode.statement.FlowControl;
import railo.transformer.bytecode.statement.FlowControlBreak;
import railo.transformer.bytecode.statement.FlowControlContinue;
import railo.transformer.bytecode.statement.FlowControlFinal;
import railo.transformer.bytecode.statement.FlowControlRetry;
import railo.transformer.bytecode.statement.PrintOut;
import railo.transformer.bytecode.statement.TryCatchFinally;
import railo.transformer.bytecode.statement.tag.Attribute;
import railo.transformer.bytecode.statement.tag.Tag;
import railo.transformer.bytecode.statement.tag.TagComponent;
import railo.transformer.bytecode.statement.tag.TagTry;
import railo.transformer.cfml.evaluator.EvaluatorException;

public final class ASMUtil {

  //private static final int VERSION_2=1;
  //private static final int VERSION_3=2;

  public static final short TYPE_ALL=0;
  public static final short TYPE_BOOLEAN=1;
  public static final short TYPE_NUMERIC=2;
  public static final short TYPE_STRING=4;
 
 
 
 
  //private static int version=0;
 
  private final static Method CONSTRUCTOR_OBJECT = Method.getMethod("void <init> ()");
  private static final Method _SRC_NAME = new Method("_srcName",
              Types.STRING,
              new Type[]{}
                );;
  //private static final String VERSION_MESSAGE = "you use an invalid version of the ASM Jar, please update your jar files";
  private static long id=0;
   
  /**
   * Gibt zurueck ob das direkt uebergeordnete Tag mit dem uebergebenen Full-Name (Namespace und Name) existiert.
   * @param el Startelement, von wo aus gesucht werden soll.
   * @param fullName Name des gesuchten Tags.
   * @return Existiert ein solches Tag oder nicht.
   */
  public static boolean hasAncestorTag(Tag tag, String fullName) {
      return getAncestorTag(tag, fullName)!=null;
  }
 

  /**
   * Gibt das uebergeordnete CFXD Tag Element zurueck, falls dies nicht existiert wird null zurueckgegeben.
   * @param el Element von dem das parent Element zurueckgegeben werden soll.
   * @return uebergeordnete CFXD Tag Element
   */
  public static Tag getParentTag(Tag tag)  {
    Statement p=tag.getParent();
    if(p==null)return null;
    p=p.getParent();
    if(p instanceof Tag) return (Tag) p;
    return null;
  }

  public static boolean isParentTag(Tag tag,String fullName)  {
    Tag p = getParentTag(tag);
    if(p==null) return false;
    return p.getFullname().equalsIgnoreCase(fullName);
   
  }
  public static boolean isParentTag(Tag tag,Class clazz)  {
    Tag p = getParentTag(tag);
    if(p==null) return false;
    return p.getClass()==clazz;
   
  }
 
  public static boolean hasAncestorRetryFCStatement(Statement stat,String label) {
    return getAncestorRetryFCStatement(stat,null,label)!=null;
  }
 
  public static boolean hasAncestorBreakFCStatement(Statement stat,String label) {
    return getAncestorBreakFCStatement(stat,null,label)!=null;
  }
 
  public static boolean hasAncestorContinueFCStatement(Statement stat,String label) {
    return getAncestorContinueFCStatement(stat,null,label)!=null;
  }
 
 
 
  public static FlowControlRetry getAncestorRetryFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) {
    return (FlowControlRetry) getAncestorFCStatement(stat, finallyLabels, FlowControl.RETRY,label);
  }
  public static FlowControlBreak getAncestorBreakFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) {
    return (FlowControlBreak) getAncestorFCStatement(stat, finallyLabels, FlowControl.BREAK,label);
  }
 
  public static FlowControlContinue getAncestorContinueFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) {
    return (FlowControlContinue) getAncestorFCStatement(stat, finallyLabels, FlowControl.CONTINUE,label);
  }

  private static FlowControl getAncestorFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, int flowType, String label) {
    Statement parent = stat;
    FlowControlFinal fcf;
    while(true)  {
      parent=parent.getParent();
      if(parent==null)return null;
      if(
         ((flowType==FlowControl.RETRY && parent instanceof FlowControlRetry) ||
         (flowType==FlowControl.CONTINUE && parent instanceof FlowControlContinue) ||
         (flowType==FlowControl.BREAK && parent instanceof FlowControlBreak))
         &&
        labelMatch((FlowControl)parent,label))  {
        if(parent instanceof ScriptBody){
          List<FlowControlFinal> _finallyLabels=finallyLabels==null?null:new ArrayList<FlowControlFinal>();
         
          FlowControl scriptBodyParent = getAncestorFCStatement(parent,_finallyLabels,flowType,label);
          if(scriptBodyParent!=null) {
            if(finallyLabels!=null){
              Iterator<FlowControlFinal> it = _finallyLabels.iterator();
              while(it.hasNext()){
                finallyLabels.add(it.next());
              }
            }
            return scriptBodyParent;
          }
          return (FlowControl)parent;
        }
        return (FlowControl) parent;
      }
     
      // only if not last
      if(finallyLabels!=null){
        fcf = parent.getFlowControlFinal();
        if(fcf!=null){
          finallyLabels.add(fcf);
        }
      }
     
    }
  }
 
  private static boolean labelMatch(FlowControl fc, String label) {
    if(StringUtil.isEmpty(label,true)) return true;
    String fcl = fc.getLabel();
    if(StringUtil.isEmpty(fcl,true)) return false;
   
    return label.trim().equalsIgnoreCase(fcl.trim());
  }


  public static void leadFlow(BytecodeContext bc,Statement stat, int flowType, String label) throws BytecodeException {
    List<FlowControlFinal> finallyLabels=new ArrayList<FlowControlFinal>();
   
    FlowControl fc;
    String name;
    if(FlowControl.BREAK==flowType) {
      fc=ASMUtil.getAncestorBreakFCStatement(stat,finallyLabels,label);
      name="break";
    }
    else if(FlowControl.CONTINUE==flowType) {
      fc=ASMUtil.getAncestorContinueFCStatement(stat,finallyLabels,label);
      name="continue";
    }
    else  {
      fc=ASMUtil.getAncestorRetryFCStatement(stat,finallyLabels,label);
      name="retry";
    }
   
    if(fc==null)
      throw new BytecodeException(name+" must be inside a loop (for,while,do-while,<cfloop>,<cfwhile> ...)",stat.getStart());
   
    GeneratorAdapter adapter = bc.getAdapter();
   
    Label end;
    if(FlowControl.BREAK==flowType) end=((FlowControlBreak)fc).getBreakLabel();
    else if(FlowControl.CONTINUE==flowType) end=((FlowControlContinue)fc).getContinueLabel();
    else  end=((FlowControlRetry)fc).getRetryLabel();

    // first jump to all final labels
    FlowControlFinal[] arr = finallyLabels.toArray(new FlowControlFinal[finallyLabels.size()]);
    if(arr.length>0) {
      FlowControlFinal fcf;
      for(int i=0;i<arr.length;i++){
        fcf=arr[i];
       
        // first
        if(i==0) {
          adapter.visitJumpInsn(Opcodes.GOTO, fcf.getFinalEntryLabel());
        }
       
        // last
        if(arr.length==i+1) fcf.setAfterFinalGOTOLabel(end);
        else fcf.setAfterFinalGOTOLabel(arr[i+1].getFinalEntryLabel());
      }
     
    }
    else bc.getAdapter().visitJumpInsn(Opcodes.GOTO, end);
  }
 
 
 
  public static boolean hasAncestorTryStatement(Statement stat) {
    return getAncestorTryStatement(stat)!=null;
  }
 
  public static Statement getAncestorTryStatement(Statement stat) {
    Statement parent = stat;
    while(true)  {
      parent=parent.getParent();
      if(parent==null)return null;
     
      if(parent instanceof TagTry)  {
        return parent;
      }
      else if(parent instanceof TryCatchFinally)  {
        return parent;
      }
    }
  }
 


 
  /**
   * Gibt ein uebergeordnetes Tag mit dem uebergebenen Full-Name (Namespace und Name) zurueck,
   * falls ein solches existiert, andernfalls wird null zurueckgegeben.
   * @param el Startelement, von wo aus gesucht werden soll.
   * @param fullName Name des gesuchten Tags.
   * @return  �bergeornetes Element oder null.
   */
  public static Tag getAncestorTag(Tag tag, String fullName) {
    Statement parent=tag;
    while(true)  {
      parent=parent.getParent();
      if(parent==null)return null;
      if(parent instanceof Tag)  {
        tag=(Tag) parent;
        if(tag.getFullname().equalsIgnoreCase(fullName))
          return tag;
      }
    }
  }
 
 

    /**
     * extract the content of a attribut
     * @param cfxdTag
     * @param attrName
     * @return attribute value
     * @throws EvaluatorException
     */
  public static Boolean getAttributeBoolean(Tag tag,String attrName) throws EvaluatorException {
    Boolean b= getAttributeLiteral(tag, attrName).getBoolean(null);
    if(b==null)throw new EvaluatorException("attribute ["+attrName+"] must be a constant boolean value");
    return b;
    }
   
    /**
     * extract the content of a attribut
     * @param cfxdTag
     * @param attrName
     * @return attribute value
     * @throws EvaluatorException
     */
  public static Boolean getAttributeBoolean(Tag tag,String attrName, Boolean defaultValue) {
    Literal lit=getAttributeLiteral(tag, attrName,null);
    if(lit==null) return defaultValue;
    return lit.getBoolean(defaultValue);
    }


    /**
     * extract the content of a attribut
     * @param cfxdTag
     * @param attrName
     * @return attribute value
     * @throws EvaluatorException
     */
  public static String getAttributeString(Tag tag,String attrName) throws EvaluatorException {
    return getAttributeLiteral(tag, attrName).getString();
    }
   
    /**
     * extract the content of a attribut
     * @param cfxdTag
     * @param attrName
     * @return attribute value
     * @throws EvaluatorException
     */
  public static String getAttributeString(Tag tag,String attrName, String defaultValue) {
    Literal lit=getAttributeLiteral(tag, attrName,null);
    if(lit==null) return defaultValue;
    return lit.getString();
    }
 
  /**
     * extract the content of a attribut
     * @param cfxdTag
     * @param attrName
     * @return attribute value
     * @throws EvaluatorException
     */
  public static Literal getAttributeLiteral(Tag tag,String attrName) throws EvaluatorException {
    Attribute attr = tag.getAttribute(attrName);
    if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue());
        throw new EvaluatorException("attribute ["+attrName+"] must be a constant value");
    }
 
 
   
    /**
     * extract the content of a attribut
     * @param cfxdTag
     * @param attrName
     * @return attribute value
     * @throws EvaluatorException
     */
  public static Literal getAttributeLiteral(Tag tag,String attrName, Literal defaultValue) {
    Attribute attr = tag.getAttribute(attrName);
    if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue());
        return defaultValue;
    }
 
 
 

  /**
   * Prueft ob das das angegebene Tag in der gleichen Ebene nach dem angegebenen Tag vorkommt.
   * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen.
   * @param nameToFind Tag Name der nicht vorkommen darf
   * @return kommt das Tag vor.
   */
  public static boolean hasSisterTagAfter(Tag tag, String nameToFind) {
    Body body=(Body) tag.getParent();
    List<Statement> stats = body.getStatements();
    Iterator<Statement> it = stats.iterator();
    Statement other;
   
    boolean isAfter=false;
    while(it.hasNext()) {
      other=it.next();
     
      if(other instanceof Tag) {
        if(isAfter) {
          if(((Tag) other).getTagLibTag().getName().equals(nameToFind))
          return true;
        }
        else if(other == tag) isAfter=true;
      }
    }
    return false;
  }
 
  /**
   * Prueft ob das angegebene Tag innerhalb seiner Ebene einmalig ist oder nicht.
   * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen.
   * @return kommt das Tag vor.
   */
  public static boolean hasSisterTagWithSameName(Tag tag) {
   
    Body body=(Body) tag.getParent();
    List<Statement> stats = body.getStatements();
    Iterator<Statement> it = stats.iterator();
    Statement other;
    String name=tag.getTagLibTag().getName();
   
    while(it.hasNext()) {
      other=it.next();
      if(other != tag && other instanceof Tag && ((Tag) other).getTagLibTag().getName().equals(name))
          return true;
     
    }
    return false;
  }

  /**
   * remove this tag from his parent body
   * @param tag
   */
  public static void remove(Tag tag) {
    Body body=(Body) tag.getParent();
    body.getStatements().remove(tag);
  }

  /**
   * replace src with trg
   * @param src
   * @param trg
   */
  public static void replace(Tag src, Tag trg, boolean moveBody) {
    trg.setParent(src.getParent());
   
    Body p=(Body) src.getParent();
    List<Statement> stats = p.getStatements();
    Iterator<Statement> it = stats.iterator();
    Statement stat;
    int count=0;
   
    while(it.hasNext()) {
      stat=it.next();
      if(stat==src) {
        if(moveBody && src.getBody()!=null)src.getBody().setParent(trg);
        stats.set(count, trg);
        break;
      }
      count++;
    }
  }
 
  public static Page getAncestorPage(Statement stat) throws BytecodeException {
    Statement parent=stat;
    while(true)  {
      parent=parent.getParent();
      if(parent==null) {
        throw new BytecodeException("missing parent Statement of Statement",stat.getStart());
        //return null;
      }
      if(parent instanceof Pagereturn (Page) parent;
    }
  }
 
  public static Page getAncestorPage(Statement stat, Page defaultValue) {
    Statement parent=stat;
    while(true)  {
      parent=parent.getParent();
      if(parent==null) {
        return defaultValue;
      }
      if(parent instanceof Pagereturn (Page) parent;
    }
  }
 
  public static void listAncestor(Statement stat) {
    Statement parent=stat;
    aprint.o(stat);
    while(true)  {
      parent=parent.getParent();
      if(parent instanceof Page)aprint.o("page-> "+ ((Page)parent).getSource());
      else aprint.o("parent-> "+ parent);
      if(parent==null) break;
    }
  }
 
 
  public static Tag getAncestorComponent(Statement stat) throws BytecodeException {
    //print.ln("getAncestorPage:"+stat);
    Statement parent=stat;
    while(true)  {
      parent=parent.getParent();
      //print.ln(" - "+parent);
      if(parent==null) {
        throw new BytecodeException("missing parent Statement of Statement",stat.getStart());
        //return null;
      }
      if(parent instanceof TagComponent)
      //if(parent instanceof Tag && "component".equals(((Tag)parent).getTagLibTag().getName())) 
        return (Tag) parent;
    }
  }
 
  public static Statement getRoot(Statement stat) {
    while(true)  {
      if(isRoot(stat))  {
        return stat;
      }
      stat=stat.getParent();
    }
  }



    public static boolean isRoot(Statement statement) {
      //return statement instanceof Page || (statement instanceof Tag && "component".equals(((Tag)statement).getTagLibTag().getName()));
      return statement instanceof Page || statement instanceof TagComponent;
    }
 
  public static void invokeMethod(GeneratorAdapter adapter, Type type, Method method) {
    if(type.getClass().isInterface())
      adapter.invokeInterface(type, method);
    else
      adapter.invokeVirtual(type, method);
  }

    public static byte[] createPojo(String className, ASMProperty[] properties,Class parent,Class[] interfaces, String srcName) throws PageException {
      className=className.replace('.', '/');
      className=className.replace('\\', '/');
      className=ListUtil.trim(className, "/");
      String[] inter=null;
      if(interfaces!=null){
        inter=new String[interfaces.length];
        for(int i=0;i<inter.length;i++){
          inter[i]=interfaces[i].getName().replace('.', '/');
        }
      }
    // CREATE CLASS 
    //ClassWriter cw = new ClassWriter(true);
      ClassWriter cw = ASMUtil.getClassWriter();
        cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC, className, null, parent.getName().replace('.', '/'), inter);
        String md5;
        try{
        md5=createMD5(properties);
      }
      catch(Throwable t){
        md5="";
        t.printStackTrace();
      }
       
        FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "_md5_", "Ljava/lang/String;", null, md5);
        fv.visitEnd();
       
       
    // Constructor
        GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_OBJECT,null,null,cw);
        adapter.loadThis();
        adapter.invokeConstructor(toType(parent,true), CONSTRUCTOR_OBJECT);
        adapter.returnValue();
        adapter.endMethod();
   
        // properties
        for(int i=0;i<properties.length;i++){
          createProperty(cw,className,properties[i]);
        }
       
        // complexType src
        if(!StringUtil.isEmpty(srcName)) {
          GeneratorAdapter _adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+ Opcodes.ACC_STATIC , _SRC_NAME, null, null, cw);
          _adapter.push(srcName);
          _adapter.returnValue();
          _adapter.endMethod();
        }
       
        cw.visitEnd();
        return cw.toByteArray();
    }
   
    private static void createProperty(ClassWriter cw,String classType, ASMProperty property) throws PageException {
    String name = property.getName();
    Type type = property.getASMType();
    Class clazz = property.getClazz();
   
    cw.visitField(Opcodes.ACC_PRIVATE, name, type.toString(), null, null).visitEnd();
   
    int load=loadFor(type);
    //int sizeOf=sizeOf(type);
   
      // get<PropertyName>():<type>
        Type[] types=new Type[0];
        Method method = new Method((clazz==boolean.class?"get":"get")+StringUtil.ucFirst(name),type,types);
            GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw);
           
            Label start = new Label();
            adapter.visitLabel(start);
           
            adapter.visitVarInsn(Opcodes.ALOAD, 0);
      adapter.visitFieldInsn(Opcodes.GETFIELD, classType, name, type.toString());
      adapter.returnValue();
     
      Label end = new Label();
      adapter.visitLabel(end);
      adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0);
      adapter.visitEnd();
     
      adapter.endMethod();
     
     
     
     
   
    // set<PropertyName>(object):void
      types=new Type[]{type};
      method = new Method("set"+StringUtil.ucFirst(name),Types.VOID,types);
            adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw);
           
            start = new Label();
            adapter.visitLabel(start);
            adapter.visitVarInsn(Opcodes.ALOAD, 0);
            adapter.visitVarInsn(load, 1);
            adapter.visitFieldInsn(Opcodes.PUTFIELD, classType, name, type.toString());
     
      adapter.visitInsn(Opcodes.RETURN);
      end = new Label();
      adapter.visitLabel(end);
      adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0);
      adapter.visitLocalVariable(name, type.toString(), null, start, end, 1);
      //adapter.visitMaxs(0, 0);//.visitMaxs(sizeOf+1, sizeOf+1);// hansx
      adapter.visitEnd();
       
      adapter.endMethod();
     
     
     
     
  }

    public static int loadFor(Type type) {
      if(type.equals(Types.BOOLEAN_VALUE) || type.equals(Types.INT_VALUE) || type.equals(Types.CHAR) || type.equals(Types.SHORT_VALUE))
        return Opcodes.ILOAD;
      if(type.equals(Types.FLOAT_VALUE))
        return Opcodes.FLOAD;
      if(type.equals(Types.LONG_VALUE))
        return Opcodes.LLOAD;
      if(type.equals(Types.DOUBLE_VALUE))
        return Opcodes.DLOAD;
      return Opcodes.ALOAD;
  }

    public static int sizeOf(Type type) {
      if(type.equals(Types.LONG_VALUE) || type.equals(Types.DOUBLE_VALUE))
        return 2;
      return 1;
  }


  /**
     * translate a string cfml type definition to a Type Object
     * @param cfType
     * @param axistype
     * @return
     * @throws PageException
     */
    public static Type toType(String cfType, boolean axistype) throws PageException {
    return toType(Caster.cfTypeToClass(cfType), axistype);
  }

    /**
     * translate a string cfml type definition to a Type Object
     * @param cfType
     * @param axistype
     * @return
     * @throws PageException
     */
    public static Type toType(Class type, boolean axistype) {
    if(axistype)type=AxisCaster.toAxisTypeClass(type);
    return Type.getType(type)
  }
   

  public static String createMD5(ASMProperty[] props) {
   
    StringBuffer sb=new StringBuffer();
    for(int i=0;i<props.length;i++){
      sb.append("name:"+props[i].getName()+";");
      if(props[i] instanceof Property){
        sb.append("type:"+((Property)props[i]).getType()+";");
      }
      else {
        try {
          sb.append("type:"+props[i].getASMType()+";");
         
        }
        catch (PageException e) {}
      }
    }
    try {
      return MD5.getDigestAsString(sb.toString());
    } catch (IOException e) {
      return "";
    }
  }



  public static void removeLiterlChildren(Tag tag, boolean recursive) {
    Body body=tag.getBody();
    if(body!=null) {
          List<Statement> list = body.getStatements();
          Statement[] stats = list.toArray(new Statement[list.size()]);
          PrintOut po;
          Tag t;
          for(int i=0;i<stats.length;i++) {
              if(stats[i] instanceof PrintOut) {
                po=(PrintOut) stats[i];
                if(po.getExpr() instanceof Literal) {
                  body.getStatements().remove(po);
                }
              }
              else if(recursive && stats[i] instanceof Tag) {
                t=(Tag) stats[i];
                if(t.getTagLibTag().isAllowRemovingLiteral()) {
                  removeLiterlChildren(t, recursive);
                }
              }
            }
        }
  }


  public synchronized static String getId() {
    if(id<0)id=0;
    return StringUtil.addZeros(++id,6);
  }


  public static boolean isEmpty(Body body) {
    return body==null || body.isEmpty();
  }


  /**
   * @param adapter
   * @param expr
   * @param mode
   */
  public static void pop(GeneratorAdapter adapter, Expression expr,int mode) {
    if(mode==Expression.MODE_VALUE && (expr instanceof ExprDouble))adapter.pop2();
    else adapter.pop();
  }
  public static void pop(GeneratorAdapter adapter, Type type) {
    if(type.equals(Types.DOUBLE_VALUE))adapter.pop2();
    else if(type.equals(Types.VOID));
    else adapter.pop();
  }


  public static ClassWriter getClassWriter() {
    return new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES);
    /*if(true) return new ClassWriter(ClassWriter.COMPUTE_MAXS);
   
   
    if(version==VERSION_2)
      return new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES);
   
    try{
      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      version=VERSION_2;
      return cw;
    }
    catch(NoSuchMethodError err){
      if(version==0){
        version=VERSION_3;
      }
     
      PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter();
      SystemOut.printDate(ew, VERSION_MESSAGE);
     
      try {
        return  ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE});
       
      }
      catch (Exception e) {
        throw new RuntimeException(Caster.toPageException(e));
       
      }
    }*/
  }

  /*
   * For 3.1
   *
   * public static ClassWriter getClassWriter() {
    if(version==VERSION_3)
      return new ClassWriter(ClassWriter.COMPUTE_MAXS);
   
    try{
      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      version=VERSION_3;
      return cw;
    }
    catch(NoSuchMethodError err){
      if(version==0){
        version=VERSION_2;
        throw new RuntimeException(new ApplicationException(VERSION_MESSAGE+
            ", after reload this version will work as well, but please update to newer version"));
      }
     
      PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter();
      SystemOut.printDate(ew, VERSION_MESSAGE);
      //err.printStackTrace(ew);
     
      try {
        return (ClassWriter) ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE});
       
      }
      catch (Exception e) {
        throw new RuntimeException(Caster.toPageException(e));
       
      }
    }
  }*/


  public static String createOverfowMethod(String prefix, int id) { // pattern is used in function callstackget
    if(StringUtil.isEmpty(prefix)) prefix="call";
    return prefix+"_"+StringUtil.addZeros(id,6);
  }
 
  public static boolean isOverfowMethod(String name) {
    return name.length()>6 && Decision.isNumeric(name.substring(name.length()-6,name.length()));
    //return name.startsWith("_call") && name.length()>=11;
  }


  public static boolean isDotKey(ExprString expr) {
    return expr instanceof LitString && !((LitString)expr).fromBracket();
  }

  public static String toString(Expression exp,String defaultValue) {
    try {
      return toString(exp);
    } catch (BytecodeException e) {
      return defaultValue;
    }
  }
  public static String toString(Expression exp) throws BytecodeException {
    if(exp instanceof Variable) {
      return toString(VariableString.toExprString(exp));
    }
    else if(exp instanceof VariableString) {
      return ((VariableString)exp).castToString();
    }
    else if(exp instanceof Literal) {
      return ((Literal)exp).toString();
    }
    return null;
  }


  public static Boolean toBoolean(Attribute attr, Position start) throws BytecodeException {
    if(attr==null)
      throw new BytecodeException("attribute does not exist",start);
   
    if(attr.getValue() instanceof Literal){
      Boolean b=((Literal)attr.getValue()).getBoolean(null);
      if(b!=null) return b;
    }
    throw new BytecodeException("attribute ["+attr.getName()+"] must be a constant boolean value",start);
   
   
  }
  public static Boolean toBoolean(Attribute attr, int line, Boolean defaultValue) {
    if(attr==null)
      return defaultValue;
   
    if(attr.getValue() instanceof Literal){
      Boolean b=((Literal)attr.getValue()).getBoolean(null);
      if(b!=null) return b;
    }
    return defaultValue; 
  }


  public static boolean isCFC(Statement s) {
    Statement p;
    while((p=s.getParent())!=null){
      s=p;
    }
   
    return true;
  }

  public static boolean isLiteralAttribute(Tag tag, String attrName, short type,boolean required,boolean throwWhenNot) throws EvaluatorException {
    return isLiteralAttribute(tag,tag.getAttribute(attrName), type, required, throwWhenNot);
  }
 
 
  public static boolean isLiteralAttribute(Tag tag,Attribute attr, short type,boolean required,boolean throwWhenNot) throws EvaluatorException {
    String strType="/constant";
    if(attr!=null && !isNull(attr.getValue())) {
     
      switch(type){
      case TYPE_ALL:
        if(attr.getValue() instanceof Literal) return true;
      break;
      case TYPE_BOOLEAN:
        if(CastBoolean.toExprBoolean(attr.getValue()) instanceof LitBoolean) return true;
        strType=" boolean";
      break;
      case TYPE_NUMERIC:
        if(CastDouble.toExprDouble(attr.getValue()) instanceof LitDouble) return true;
        strType=" numeric";
      break;
      case TYPE_STRING:
        if(CastString.toExprString(attr.getValue()) instanceof LitString) return true;
        strType=" string";
      break;
      }
      if(!throwWhenNot) return false;
      throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] must be a literal"+strType+" value. "+
          "attributes java class type "+attr.getValue().getClass().getName());
    }
    if(required){
      if(!throwWhenNot) return false;
      throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] is required");
    }
    return false;
  }


  public static boolean isNull(Expression expr) {
    if(expr instanceof NullExpression) return true;
    if(expr instanceof Cast) {
      return isNull(((Cast)expr).getExpr());
    }
    return false;
  }


  public static boolean isRefType(Type type) {
    return
    !(type==Types.BYTE_VALUE || type==Types.BOOLEAN_VALUE || type==Types.CHAR || type==Types.DOUBLE_VALUE ||
    type==Types.FLOAT_VALUE || type==Types.INT_VALUE || type==Types.LONG_VALUE || type==Types.SHORT_VALUE);
  }


  public static Type toRefType(Type type) {
    if(type==Types.BYTE_VALUE) return Types.BYTE;
    if(type==Types.BOOLEAN_VALUE) return Types.BOOLEAN;
    if(type==Types.CHAR) return Types.CHARACTER;
    if(type==Types.DOUBLE_VALUE) return Types.DOUBLE;
    if(type==Types.FLOAT_VALUE) return Types.FLOAT;
    if(type==Types.INT_VALUE) return Types.INTEGER;
    if(type==Types.LONG_VALUE) return Types.LONG;
    if(type==Types.SHORT_VALUE) return Types.SHORT;
   
    return type;
  }
 
  /**
   * return value type only when there is one
   * @param type
   * @return
   */
  public static Type toValueType(Type type) {
    if(type==Types.BYTE) return Types.BYTE_VALUE;
    if(type==Types.BOOLEAN) return Types.BOOLEAN_VALUE;
    if(type==Types.CHARACTER) return Types.CHAR;
    if(type==Types.DOUBLE) return Types.DOUBLE_VALUE;
    if(type==Types.FLOAT) return Types.FLOAT_VALUE;
    if(type==Types.INTEGER) return Types.INT_VALUE;
    if(type==Types.LONG) return Types.LONG_VALUE;
    if(type==Types.SHORT) return Types.SHORT_VALUE;
   
    return type;
  }


  public static Class getValueTypeClass(Type type, Class defaultValue) {

    if(type==Types.BYTE_VALUE) return byte.class;
    if(type==Types.BOOLEAN_VALUE) return boolean.class;
    if(type==Types.CHAR) return char.class;
    if(type==Types.DOUBLE_VALUE) return double.class;
    if(type==Types.FLOAT_VALUE) return float.class;
    if(type==Types.INT_VALUE) return int.class;
    if(type==Types.LONG_VALUE) return long.class;
    if(type==Types.SHORT_VALUE) return short.class;
   
    return defaultValue;
  }


  public static ASMProperty[] toASMProperties(Property[] properties) {
    ASMProperty[] asmp=new ASMProperty[properties.length];
    for(int i=0;i<asmp.length;i++){
      asmp[i]=(ASMProperty) properties[i];
    }
    return asmp;
  }
 

  public static boolean containsComponent(Body body) {
    if(body==null) return false;
   
    Iterator<Statement> it = body.getStatements().iterator();
    while(it.hasNext()){
      if(it.next() instanceof TagComponent)return true;
    }
    return false;
  }


  public static void dummy1(BytecodeContext bc) {
    bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J");
    bc.getAdapter().visitInsn(Opcodes.POP2);
  }
  public static void dummy2(BytecodeContext bc) {
    bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "nanoTime", "()J");
    bc.getAdapter().visitInsn(Opcodes.POP2);
  }


  /**
   * convert a clas array to a type array
   * @param classes
   * @return
   */
  public static Type[] toTypes(Class<?>[] classes) {
    if(classes==null || classes.length==0)
      return new Type[0];
   
    Type[] types=new Type[classes.length];
    for(int i=0;i<classes.length;i++)  {
      types[i]=Type.getType(classes[i]);
    }
    return types;
  }


  public static String display(ExprString name) {
    if(name instanceof Literal) {
      if(name instanceof Identifier)
        return ((Identifier)name).getRaw();
      return ((Literal)name).getString();
     
    }
    return name.toString();
  }


  public static long timeSpanToLong(Expression val) throws EvaluatorException {
    if(val instanceof Literal) {
      Double d = ((Literal)val).getDouble(null);
      if(d==null) throw cacheWithinException();
      return TimeSpanImpl.fromDays(d.doubleValue()).getMillis();
    }
    // createTimespan
    else if(val instanceof Variable) {
      Variable var=(Variable)val;
      if(var.getMembers().size()==1) {
        Member first = var.getFirstMember();
        if(first instanceof BIF) {
          BIF bif=(BIF) first;
          if("createTimeSpan".equalsIgnoreCase(bif.getFlf().getName())) {
            Argument[] args = bif.getArguments();
            int len=ArrayUtil.size(args);
            if(len>=4 && len<=5) {
              double days=toDouble(args[0].getValue());
              double hours=toDouble(args[1].getValue());
              double minutes=toDouble(args[2].getValue());
              double seconds=toDouble(args[3].getValue());
              double millis=len==5?toDouble(args[4].getValue()):0;
              return new TimeSpanImpl((int)days,(int)hours,(int)minutes,(int)seconds,(int)millis).getMillis();
            }
          }
        }
      }
    }
    throw cacheWithinException();
  }



  private static EvaluatorException cacheWithinException() {
    return new EvaluatorException("value of cachedWithin must be a literal timespan, like 0.1 or createTimespan(1,2,3,4)");
  }


  private static double toDouble(Expression e) throws EvaluatorException {
    if(!(e instanceof Literal))
      throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context");
    Double d = ((Literal)e).getDouble(null);
    if(d==null)
      throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context");
   
    return d.doubleValue();
  }

  public static void visitLabel(GeneratorAdapter ga, Label label) {
    if(label!=null) ga.visitLabel(label);
  }
 

 
  public static String getClassName(Resource res) throws IOException{
    byte[] src=IOUtil.toBytes(res);
    ClassReader cr = new ClassReader(src);
    return cr.getClassName();
  }
 
  public static String getClassName(byte[] barr){
    return new ClassReader(barr).getClassName();
  }


  public static String getSourceName(Class clazz) throws IOException {
    return SourceNameClassVisitor.getSourceName(clazz);
  }

  public static boolean hasOnlyDataMembers(Variable var) {
    Iterator<Member> it = var.getMembers().iterator();
    Member m;
    while(it.hasNext()){
      m = it.next();
      if(!(m instanceof DataMember)) return false;
    }
    return true;
  }
 
}
TOP

Related Classes of railo.transformer.bytecode.util.ASMUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.