Package railo.transformer.bytecode

Source Code of railo.transformer.bytecode.SourceLastModifiedClassAdapter

package railo.transformer.bytecode;

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

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

import railo.commons.io.CharsetUtil;
import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.commons.lang.NumberUtil;
import railo.commons.lang.StringUtil;
import railo.runtime.Mapping;
import railo.runtime.PageSource;
import railo.runtime.component.ImportDefintion;
import railo.runtime.component.ImportDefintionImpl;
import railo.runtime.config.Config;
import railo.runtime.exp.TemplateException;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.StructImpl;
import railo.runtime.type.UDF;
import railo.runtime.type.scope.Undefined;
import railo.runtime.type.util.KeyConstants;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.literal.LitString;
import railo.transformer.bytecode.literal.LitString.Range;
import railo.transformer.bytecode.statement.Argument;
import railo.transformer.bytecode.statement.HasBodies;
import railo.transformer.bytecode.statement.HasBody;
import railo.transformer.bytecode.statement.IFunction;
import railo.transformer.bytecode.statement.NativeSwitch;
import railo.transformer.bytecode.statement.tag.Attribute;
import railo.transformer.bytecode.statement.tag.Tag;
import railo.transformer.bytecode.statement.tag.TagImport;
import railo.transformer.bytecode.statement.tag.TagThread;
import railo.transformer.bytecode.statement.udf.Function;
import railo.transformer.bytecode.statement.udf.FunctionImpl;
import railo.transformer.bytecode.util.ASMConstants;
import railo.transformer.bytecode.util.ASMUtil;
import railo.transformer.bytecode.util.ExpressionUtil;
import railo.transformer.bytecode.util.Types;
import railo.transformer.bytecode.visitor.ArrayVisitor;
import railo.transformer.bytecode.visitor.ConditionVisitor;
import railo.transformer.bytecode.visitor.DecisionIntVisitor;
import railo.transformer.bytecode.visitor.OnFinally;
import railo.transformer.bytecode.visitor.TryCatchFinallyVisitor;

/**
* represent a single Page like "index.cfm"
*/
public final class Page extends BodyBase {


  public void doFinalize(BytecodeContext bc) {
    ExpressionUtil.visitLine(bc, getEnd());
  }
 
  public static final Type NULL = Type.getType(railo.runtime.type.Null.class);
  public static final Type KEY_IMPL = Type.getType(KeyImpl.class);
  public static final Type KEY_CONSTANTS = Type.getType(KeyConstants.class);
  public static final Method KEY_INIT = new Method(
      "init",
      Types.COLLECTION_KEY,
      new Type[]{Types.STRING}
        );
  public static final Method KEY_INTERN = new Method(
      "intern",
      Types.COLLECTION_KEY,
      new Type[]{Types.STRING}
        );
 
  // public static ImportDefintion getInstance(String fullname,ImportDefintion defaultValue)
  private static final Method ID_GET_INSTANCE = new Method(
      "getInstance",
      Types.IMPORT_DEFINITIONS,
      new Type[]{Types.STRING,Types.IMPORT_DEFINITIONS}
        );

  public final static Method STATIC_CONSTRUCTOR = Method.getMethod("void <clinit> ()V");
  //public final static Method CONSTRUCTOR = Method.getMethod("void <init> ()V");

  private static final Method CONSTRUCTOR = new Method(
      "<init>",
      Types.VOID,
      new Type[]{}//
        );
  private static final Method CONSTRUCTOR_PS = new Method(
      "<init>",
      Types.VOID,
      new Type[]{Types.PAGE_SOURCE}//
        );

    public static final Type STRUCT_IMPL = Type.getType(StructImpl.class);
  private static final Method INIT_STRUCT_IMPL = new Method(
      "<init>",
      Types.VOID,
      new Type[]{}
        );

 
    // void call (railo.runtime.PageContext)
    private final static Method CALL = new Method(
      "call",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT}
        );
   
    /*/ void _try ()
    private final static Method TRY = new Method(
      "_try",
      Types.VOID,
      new Type[]{}
        );*/
     
    // int getVersion()
    private final static Method VERSION = new Method(
      "getVersion",
      Types.INT_VALUE,
      new Type[]{}
        );
    // void _init()
    private final static Method _INIT = new Method(
      "initKeys",
      Types.VOID,
      new Type[]{}
        );
   
    private final static Method SET_PAGE_SOURCE = new Method(
      "setPageSource",
      Types.VOID,
      new Type[]{Types.PAGE_SOURCE}
        );
   
    // public ImportDefintion[] getImportDefintions()
    private final static Method GET_IMPORT_DEFINITIONS = new Method(
      "getImportDefintions",
      Types.IMPORT_DEFINITIONS_ARRAY,
      new Type[]{}
        );
   
    // long getSourceLastModified()
    private final static Method LAST_MOD = new Method(
      "getSourceLastModified",
      Types.LONG_VALUE,
      new Type[]{}
        );
   
    private final static Method COMPILE_TIME = new Method(
      "getCompileTime",
      Types.LONG_VALUE,
      new Type[]{}
        );

    private static final Type USER_DEFINED_FUNCTION = Type.getType(UDF.class);
    private static final Method UDF_CALL = new Method(
      "udfCall",
      Types.OBJECT,
      new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE}
      );
   

  private static final Method THREAD_CALL = new Method(
      "threadCall",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE}
      );

  /*private static final Method UDF_DEFAULT_VALUE = new Method(
      "udfDefaultValue",
      Types.OBJECT,
      new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE}
      );*/
 
  private static final Method UDF_DEFAULT_VALUE = new Method(
      "udfDefaultValue",
      Types.OBJECT,
      new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT}
      );

  private static final Method NEW_COMPONENT_IMPL_INSTANCE = new Method(
      "newInstance",
      Types.COMPONENT_IMPL,
      new Type[]{Types.PAGE_CONTEXT,Types.STRING,Types.BOOLEAN_VALUE}
        );
 
  private static final Method NEW_INTERFACE_IMPL_INSTANCE = new Method(
      "newInstance",
      Types.INTERFACE_IMPL,
      new Type[]{Types.STRING,Types.BOOLEAN_VALUE,Types.MAP}
        );
 
 

 

  // void init(PageContext pc,Component Impl c) throws PageException
  private static final Method INIT_COMPONENT = new Method(
      "initComponent",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_IMPL}
        );
  private static final Method INIT_INTERFACE = new Method(
      "initInterface",
      Types.VOID,
      new Type[]{Types.INTERFACE_IMPL}
        );
 

  // public boolean setMode(int mode) {
  private static final Method SET_MODE = new Method(
      "setMode",
      Types.INT_VALUE,
      new Type[]{Types.INT_VALUE}
        );
 
 


 
 


  private static final Method CONSTR_INTERFACE_IMPL = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.INTERFACE_PAGE,
            Types.STRING, // extends
            Types.STRING, // hind
            Types.STRING, // display
            Types.STRING, // callpath
            Types.BOOLEAN_VALUE, // realpath
            Types.MAP, //interfaceudfs
            Types.MAP // meta
          }
        );
 
 
  //void init(PageContext pageContext,ComponentPage componentPage)
  private static final Method INIT = new Method(
      "init",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE}
        );
 
  private static final Method CHECK_INTERFACE = new Method(
      "checkInterface",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE}
        );
 
 

  // boolean getOutput()
  private static final Method GET_OUTPUT = new Method(
      "getOutput",
      Types.BOOLEAN_VALUE,
      new Type[]{}
        );


  private static final Method PUSH_BODY = new Method(
      "pushBody",
      Types.BODY_CONTENT,
      new Type[]{}
        );
 
  /*/ boolean setSilent()
  private static final Method SET_SILENT = new Method(
      "setSilent",
      Types.BOOLEAN_VALUE,
      new Type[]{}
        );
*/
  // Scope beforeCall(PageContext pc)
  private static final Method BEFORE_CALL = new Method(
      "beforeCall",
      Types.VARIABLES,
      new Type[]{Types.PAGE_CONTEXT}
        );

  private static final Method TO_PAGE_EXCEPTION = new Method(
      "toPageException",
      Types.PAGE_EXCEPTION,
      new Type[]{Types.THROWABLE});
 
 
  // boolean unsetSilent()
  /*private static final Method UNSET_SILENT = new Method(
      "unsetSilent",
      Types.BOOLEAN_VALUE,
      new Type[]{}
        );*/

  // void afterCall(PageContext pc, Scope parent)
  private static final Method AFTER_CALL = new Method(
      "afterConstructor",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT,Types.VARIABLES}
        );

  // ComponentImpl(ComponentPage,boolean, String, String, String) NS==No Style
 
 
  // Component Impl(ComponentPage,boolean, String, String, String, String) WS==With Style
  private static final Method CONSTR_COMPONENT_IMPL = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COMPONENT_PAGE,
          Types.BOOLEAN,
          Types.BOOLEAN_VALUE,
          Types.STRING,
          Types.STRING,
          Types.STRING,
          Types.STRING,
          Types.STRING,
          Types.BOOLEAN_VALUE,
          Types.STRING,
          Types.BOOLEAN_VALUE,
          Types.BOOLEAN_VALUE,
          STRUCT_IMPL
        }
        );
  private static final Method SET_EL = new Method(
      "setEL",
      Types.OBJECT,
      new Type[]{Types.STRING,Types.OBJECT}
        );
  private static final Method UNDEFINED_SCOPE = new Method(
      "us",
      Types.UNDEFINED,
      new Type[]{}
        );
  private static final Method FLUSH_AND_POP = new Method(
      "flushAndPop",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT}
        );
  private static final Method CLEAR_AND_POP = new Method(
      "clearAndPop",
      Types.VOID,
      new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT}
        );
  public static final byte CF = (byte)207;
  public static final byte _33 = (byte)51;
  private static final boolean ADD_C33 = false;
  //private static final String SUB_CALL_UDF = "udfCall";
  private static final String SUB_CALL_UDF = "_";
  private static final int DEFAULT_VALUE = 3;
   
    private int version;
    private long lastModifed;
    private String name;
   
    //private Body body=new Body();
  private Resource source;
  private final String path;
  private boolean isComponent;
  private boolean isInterface;

  private List<IFunction> functions=new ArrayList<IFunction>();
  private List<TagThread> threads=new ArrayList<TagThread>();
  private boolean _writeLog;
  private boolean supressWSbeforeArg;
  private Resource staticTextLocation;
  private int len;
  private int off;
  private int methodCount=0;
  private final Config config;
   
 
 
    public Page(Config config,Resource source,String name,int version, long lastModifed, boolean writeLog, boolean supressWSbeforeArg) {
      name=name.replace('.', '/');
      //body.setParent(this);
        this.name=name;
        this.version=version;
        this.lastModifed=lastModifed;
        this.source=source;
        this.path=source.getAbsolutePath();
       
        this._writeLog=writeLog;
        this.supressWSbeforeArg=supressWSbeforeArg;
        this.config=config;
    }
   
    /**
     * result byte code as binary array
     * @param classFile
     * @return byte code
     * @throws IOException
     * @throws TemplateException
     */
    public byte[] execute(PageSource source,Resource classFile) throws BytecodeException {
      Resource p = classFile.getParentResource().getRealResource(classFile.getName()+".txt");
       
      List<LitString> keys=new ArrayList<LitString>();
      ClassWriter cw = ASMUtil.getClassWriter();
      //ClassWriter cw = new ClassWriter(true);
     
      ArrayList<String> imports = new ArrayList<String>();
        getImports(imports, this);
     
      // parent
      String parent="railo/runtime/PagePlus";
      if(isComponent()) parent="railo/runtime/ComponentPage";
      else if(isInterface()) parent="railo/runtime/InterfacePage";
     
      cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL, name, null, parent, null);
        cw.visitSource(this.path, null);

        // static constructor
        //GeneratorAdapter statConstrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,STATIC_CONSTRUCTOR,null,null,cw);
    BytecodeContext statConstr = null;//new BytecodeContext(null,null,this,externalizer,keys,cw,name,statConstrAdapter,STATIC_CONSTRUCTOR,writeLog(),supressWSbeforeArg);
   
        // constructor
      GeneratorAdapter constrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_PS,null,null,cw);
    BytecodeContext constr = new BytecodeContext(source,null,null,this,keys,cw,name,constrAdapter,CONSTRUCTOR_PS,writeLog(),supressWSbeforeArg);
    constrAdapter.loadThis();
        Type t=Types.PAGE_PLUS;
        if(isComponent())t=Types.COMPONENT_PAGE;
        else if(isInterface())t=Types.INTERFACE_PAGE;
       
        constrAdapter.invokeConstructor(t, CONSTRUCTOR);
       
     // call _init()
        constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
        constrAdapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, constr.getClassName(), "initKeys", "()V");

     // private static  ImportDefintion[] test=new ImportDefintion[]{...};
      {
      FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL,
          "imports", "[Lrailo/runtime/component/ImportDefintion;", null, null);
      fv.visitEnd();
   
      constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
      ArrayVisitor av=new ArrayVisitor();
      av.visitBegin(constrAdapter,Types.IMPORT_DEFINITIONS,imports.size());
      int index=0;
      Iterator<String> it = imports.iterator();
      while(it.hasNext()){
        av.visitBeginItem(constrAdapter,index++);
        constrAdapter.push(it.next());
        ASMConstants.NULL(constrAdapter);
        constrAdapter.invokeStatic(Types.IMPORT_DEFINITIONS_IMPL, ID_GET_INSTANCE);
        av.visitEndItem(constrAdapter);
      }
      av.visitEnd();
      constrAdapter.visitFieldInsn(Opcodes.PUTFIELD, name, "imports", "[Lrailo/runtime/component/ImportDefintion;");
       
    }
       
       
       
       
     // getVersion
         GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , VERSION, null, null, cw);
         adapter.push(version);
         adapter.returnValue();
         adapter.endMethod();
        
        
    // public ImportDefintion[] getImportDefintions()
         if(imports.size()>0){
           adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw);
           adapter.visitVarInsn(Opcodes.ALOAD, 0);
             adapter.visitFieldInsn(Opcodes.GETFIELD, name, "imports", "[Lrailo/runtime/component/ImportDefintion;");
           adapter.returnValue();
             adapter.endMethod();
         }
         else {
           adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw);
           adapter.visitInsn(Opcodes.ICONST_0);
           adapter.visitTypeInsn(Opcodes.ANEWARRAY, "railo/runtime/component/ImportDefintion");
           adapter.returnValue();
             adapter.endMethod();
         }

        
    // getSourceLastModified
        adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , LAST_MOD, null, null, cw);
        adapter.push(lastModifed);
        adapter.returnValue();
        adapter.endMethod();
       
    // getCompileTime
        adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , COMPILE_TIME, null, null, cw);
        adapter.push(System.currentTimeMillis());
        adapter.returnValue();
        adapter.endMethod();
  
    // newInstance/initComponent/call
        if(isComponent()) {
          Tag component=getComponent();
             writeOutNewComponent(statConstr,constr,keys,cw,component);
          writeOutInitComponent(statConstr,constr,keys,cw,component);
        }
        else if(isInterface()) {
          Tag interf=getInterface();
             writeOutNewInterface(statConstr,constr,keys,cw,interf);
          writeOutInitInterface(statConstr,constr,keys,cw,interf);
        }
        else {
          writeOutCall(statConstr,constr,keys,cw);
        }
       
// udfCall    
        Function[] functions=getFunctions();
        ConditionVisitor cv;
        DecisionIntVisitor div;
    // less/equal than 10 functions
        if(isInterface()){}
        else if(functions.length<=10) {
          adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw);
            BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_CALL,writeLog(),supressWSbeforeArg);
            if(functions.length==0){}
            else if(functions.length==1){
            ExpressionUtil.visitLine(bc,functions[0].getStart());
            functions[0].getBody().writeOut(bc);
            ExpressionUtil.visitLine(bc,functions[0].getEnd());
          }
          else writeOutUdfCallInner(bc,functions,0,functions.length);
            adapter.visitInsn(Opcodes.ACONST_NULL);
            adapter.returnValue();
            adapter.endMethod();
        }
   // more than 10 functions
        else {
          adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw);
          BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_CALL,writeLog(),supressWSbeforeArg);
            cv = new ConditionVisitor();
            cv.visitBefore();
            int count=0;
            for(int i=0;i<functions.length;i+=10) {
              cv.visitWhenBeforeExpr();
                div=new DecisionIntVisitor();
            div.visitBegin();
              adapter.loadArg(2);
            div.visitLT();
              adapter.push(i+10);
            div.visitEnd(bc);
              cv.visitWhenAfterExprBeforeBody(bc);
               
                adapter.visitVarInsn(Opcodes.ALOAD, 0);
                adapter.visitVarInsn(Opcodes.ALOAD, 1);
                adapter.visitVarInsn(Opcodes.ALOAD, 2);
                adapter.visitVarInsn(Opcodes.ILOAD, 3);
                adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, createFunctionName(++count), "(Lrailo/runtime/PageContext;Lrailo/runtime/type/UDF;I)Ljava/lang/Object;");
                adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue();
              cv.visitWhenAfterBody(bc);
            }
            cv.visitAfter(bc);
         
          adapter.visitInsn(Opcodes.ACONST_NULL);
          adapter.returnValue();
          adapter.endMethod();
         
          count=0;
          Method innerCall;
          for(int i=0;i<functions.length;i+=10) {
            innerCall = new Method(createFunctionName(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE});
           
            adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerCall, null, new Type[]{Types.THROWABLE}, cw);
            writeOutUdfCallInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,innerCall,writeLog(),supressWSbeforeArg), functions, i, i+10>functions.length?functions.length:i+10);
           
            adapter.visitInsn(Opcodes.ACONST_NULL);
            adapter.returnValue();
            adapter.endMethod();
          }
        }
       

     // threadCall
         TagThread[] threads=getThreads();
         if(true) {
           adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , THREAD_CALL, null, new Type[]{Types.THROWABLE}, cw);
           if(threads.length>0) writeOutThreadCallInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,THREAD_CALL,writeLog(),supressWSbeforeArg),threads,0,threads.length);
         //adapter.visitInsn(Opcodes.ACONST_NULL);
         adapter.returnValue();
         adapter.endMethod();
         }
       

       
               
// udfDefaultValue
    // less/equal than 10 functions
        if(isInterface()) {}
        else if(functions.length<=10) {
          adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
          if(functions.length>0)
            writeUdfDefaultValueInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),supressWSbeforeArg),functions,0,functions.length);
           
            adapter.loadArg(DEFAULT_VALUE);
          adapter.returnValue();
            adapter.endMethod();
        }
        else {
          adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
            BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),supressWSbeforeArg);
          cv = new ConditionVisitor();
          cv.visitBefore();
          int count=0;
          for(int i=0;i<functions.length;i+=10) {
            cv.visitWhenBeforeExpr();
              div=new DecisionIntVisitor();
          div.visitBegin();
            adapter.loadArg(1);
          div.visitLT();
            adapter.push(i+10);
          div.visitEnd(bc);
            cv.visitWhenAfterExprBeforeBody(bc);
             
              adapter.visitVarInsn(Opcodes.ALOAD, 0);
              adapter.visitVarInsn(Opcodes.ALOAD, 1);
              adapter.visitVarInsn(Opcodes.ILOAD, 2);
              adapter.visitVarInsn(Opcodes.ILOAD, 3);
              adapter.visitVarInsn(Opcodes.ALOAD, 4);
             
              adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, "udfDefaultValue"+(++count), "(Lrailo/runtime/PageContext;IILjava/lang/Object;)Ljava/lang/Object;");
              adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue();
             
            cv.visitWhenAfterBody(bc);
          }
          cv.visitAfter(bc);
       
        adapter.visitInsn(Opcodes.ACONST_NULL);
        adapter.returnValue();
        adapter.endMethod();
       
        count=0;
        Method innerDefaultValue;
        for(int i=0;i<functions.length;i+=10) {
          innerDefaultValue = new Method("udfDefaultValue"+(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT});
          adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerDefaultValue, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
          writeUdfDefaultValueInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,innerDefaultValue,writeLog(),supressWSbeforeArg), functions, i, i+10>functions.length?functions.length:i+10);
         
          adapter.loadArg(DEFAULT_VALUE);
          //adapter.visitInsn(Opcodes.ACONST_NULL);
          adapter.returnValue();
          adapter.endMethod();
        }
         
        }
       
       
        // register fields
        {
          GeneratorAdapter aInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , _INIT, null, null, cw);
            BytecodeContext bcInit = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,aInit,_INIT,writeLog(),supressWSbeforeArg);
          registerFields(bcInit,keys);
          aInit.returnValue();
          aInit.endMethod();
        }

        //setPageSource(pageSource);
        constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
        constrAdapter.visitVarInsn(Opcodes.ALOAD, 1);
        constrAdapter.invokeVirtual(t, SET_PAGE_SOURCE);
       
       

        //statConstr.getAdapter().returnValue();
        //statConstr.getAdapter().endMethod();
       
       
        constrAdapter.returnValue();
        constrAdapter.endMethod();
     
        if(ADD_C33) {
          byte[] tmp = cw.toByteArray();
          byte[] bLastMod=NumberUtil.longToByteArray(lastModifed);
          byte[] barr = new byte[tmp.length+10];
          // Magic Number
          barr[0]=CF; // CF
          barr[1]=_33; // 33
         
          // Last Modified
          for(int i=0;i<8;i++){
            barr[i+2]=bLastMod[i];
          }
          for(int i=0;i<tmp.length;i++){
            barr[i+10]=tmp[i];
          }
          return barr;
        }
        return cw.toByteArray();
  
    }
   



  private String createFunctionName(int i) {
    return "udfCall"+Integer.toString(i, Character.MAX_RADIX);
  }

  private boolean writeLog() {
    return _writeLog && !isInterface();
  }

  public static void registerFields(BytecodeContext bc, List<LitString> keys) throws BytecodeException {
    //if(keys.size()==0) return;
    GeneratorAdapter ga = bc.getAdapter();
   
    FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE ,
        "keys", Types.COLLECTION_KEY_ARRAY.toString(), null, null);
    fv.visitEnd();
   
    int index=0;
    LitString value;
    Iterator<LitString> it = keys.iterator();
    ga.visitVarInsn(Opcodes.ALOAD, 0);
    ga.push(keys.size());
    ga.newArray(Types.COLLECTION_KEY);
    while(it.hasNext()) {
      value=it.next();
      ga.dup();
      ga.push(index++);
      //value.setExternalize(false);
      ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF);
      ga.invokeStatic(KEY_IMPL, KEY_INTERN);
      ga.visitInsn(Opcodes.AASTORE);
    }
    ga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "keys", Types.COLLECTION_KEY_ARRAY.toString());
  }

  private void writeUdfDefaultValueInner(BytecodeContext bc, Function[] functions, int offset, int length) throws BytecodeException {
    GeneratorAdapter adapter = bc.getAdapter();
    ConditionVisitor cv = new ConditionVisitor();
    DecisionIntVisitor div;
        cv.visitBefore();
        for(int i=offset;i<length;i++) {
          cv.visitWhenBeforeExpr();
            div = new DecisionIntVisitor();
        div.visitBegin();
          adapter.loadArg(1);
        div.visitEQ();
          adapter.push(i);
        div.visitEnd(bc);
          cv.visitWhenAfterExprBeforeBody(bc);
            writeOutFunctionDefaultValueInnerInner(bc, functions[i]);
          cv.visitWhenAfterBody(bc);
        }
        cv.visitAfter(bc);
  }


  private void writeOutUdfCallInnerIf(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException {
    GeneratorAdapter adapter = bc.getAdapter();
    ConditionVisitor cv=new ConditionVisitor();
        DecisionIntVisitor div;
        cv.visitBefore();
        for(int i=offset;i<length;i++) {
          cv.visitWhenBeforeExpr();
            div=new DecisionIntVisitor();
        div.visitBegin();
          adapter.loadArg(2);
        div.visitEQ();
          adapter.push(i);
        div.visitEnd(bc);
          cv.visitWhenAfterExprBeforeBody(bc);
            ExpressionUtil.visitLine(bc, functions[i].getStart());
            functions[i].getBody().writeOut(bc);
            ExpressionUtil.visitLine(bc, functions[i].getEnd());
          cv.visitWhenAfterBody(bc);
        }
        cv.visitAfter(bc);
  }

  private void writeOutUdfCallInner(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException {
    NativeSwitch ns=new NativeSwitch(2,NativeSwitch.ARG_REF,null,null);
   
    for(int i=offset;i<length;i++) {
          ns.addCase(i, functions[i].getBody(),functions[i].getStart(),functions[i].getEnd(),true);
        }
        ns._writeOut(bc);
  }
 
 

  private void writeOutThreadCallInner(BytecodeContext bc,TagThread[] threads, int offset, int length) throws BytecodeException {
    GeneratorAdapter adapter = bc.getAdapter();
    ConditionVisitor cv=new ConditionVisitor();
        DecisionIntVisitor div;
        cv.visitBefore();
        //print.ln("functions:"+functions.length);
          for(int i=offset;i<length;i++) {
            cv.visitWhenBeforeExpr();
              div=new DecisionIntVisitor();
          div.visitBegin();
            adapter.loadArg(1);
          div.visitEQ();
            adapter.push(i);
          div.visitEnd(bc);
            cv.visitWhenAfterExprBeforeBody(bc);
              Body body = threads[i].getRealBody();
              if(body!=null)body.writeOut(bc);
            cv.visitWhenAfterBody(bc);
          }
        cv.visitAfter(bc);
  }

  private void writeOutInitComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag component) throws BytecodeException {
    final GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_COMPONENT, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
        BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,INIT_COMPONENT,writeLog(),supressWSbeforeArg);
    Label methodBegin=new Label();
      Label methodEnd=new Label();

    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
      adapter.visitLabel(methodBegin);
       
    // Scope oldData=null;
    final int oldData=adapter.newLocal(Types.VARIABLES);
    ASMConstants.NULL(adapter);
    adapter.storeLocal(oldData);
   
    int localBC=adapter.newLocal(Types.BODY_CONTENT);
    ConditionVisitor cv=new ConditionVisitor();
    cv.visitBefore();
      cv.visitWhenBeforeExpr();
        adapter.loadArg(1);
        adapter.invokeVirtual(Types.COMPONENT_IMPL, GET_OUTPUT);
      cv.visitWhenAfterExprBeforeBody(bc);
        ASMConstants.NULL(adapter);
      cv.visitWhenAfterBody(bc);

      cv.visitOtherviseBeforeBody();
        adapter.loadArg(0);
        adapter.invokeVirtual(Types.PAGE_CONTEXT, PUSH_BODY);
      cv.visitOtherviseAfterBody();
    cv.visitAfter(bc);
    adapter.storeLocal(localBC);
   
    // c.init(pc,this);
    adapter.loadArg(1);
    adapter.loadArg(0);
    adapter.visitVarInsn(Opcodes.ALOAD, 0);
    adapter.invokeVirtual(Types.COMPONENT_IMPL, INIT);
     
     
    //int oldCheckArgs=  pc.undefinedScope().setMode(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS);
      final int oldCheckArgs = adapter.newLocal(Types.INT_VALUE);
      adapter.loadArg(0);
      adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE);
      adapter.push(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS);
      adapter.invokeInterface(Types.UNDEFINED, SET_MODE);
      adapter.storeLocal(oldCheckArgs);
   
     
    TryCatchFinallyVisitor tcf=new TryCatchFinallyVisitor(new OnFinally() {
     
      public void writeOut(BytecodeContext bc) {

        // undefined.setMode(oldMode);
        adapter.loadArg(0);
        adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE);
        adapter.loadLocal(oldCheckArgs,Types.INT_VALUE);
        adapter.invokeInterface(Types.UNDEFINED, SET_MODE);
        adapter.pop();
       
          // c.afterCall(pc,_oldData);
          adapter.loadArg(1);
          adapter.loadArg(0);
          adapter.loadLocal(oldData);
          adapter.invokeVirtual(Types.COMPONENT_IMPL, AFTER_CALL);
       
       
      }
    },null);
    tcf.visitTryBegin(bc);
      // oldData=c.beforeCall(pc);
      adapter.loadArg(1);
      adapter.loadArg(0);
      adapter.invokeVirtual(Types.COMPONENT_IMPL, BEFORE_CALL);
      adapter.storeLocal(oldData);
      ExpressionUtil.visitLine(bc, component.getStart());
      writeOutCallBody(bc,component.getBody(),IFunction.PAGE_TYPE_COMPONENT);
      ExpressionUtil.visitLine(bc, component.getEnd());
    int t = tcf.visitTryEndCatchBeging(bc);
      // BodyContentUtil.flushAndPop(pc,bc);
      adapter.loadArg(0);
      adapter.loadLocal(localBC);
      adapter.invokeStatic(Types.BODY_CONTENT_UTIL, FLUSH_AND_POP);
   
      // throw Caster.toPageException(t);
      adapter.loadLocal(t);
      adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION);
      adapter.throwException();
    tcf.visitCatchEnd(bc);
   
    adapter.loadArg(0);
    adapter.loadLocal(localBC);
    adapter.invokeStatic(Types.BODY_CONTENT_UTIL, CLEAR_AND_POP);
 
      adapter.returnValue();
      adapter.visitLabel(methodEnd);
     
      adapter.endMethod();
     
  }

  private void writeOutInitInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag interf) throws BytecodeException {
    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_INTERFACE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
        BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,INIT_INTERFACE,writeLog(),supressWSbeforeArg);
    Label methodBegin=new Label();
      Label methodEnd=new Label();

    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
      adapter.visitLabel(methodBegin);
       
      ExpressionUtil.visitLine(bc, interf.getStart());
    writeOutCallBody(bc,interf.getBody(),IFunction.PAGE_TYPE_INTERFACE);
    ExpressionUtil.visitLine(bc, interf.getEnd());
   
      adapter.returnValue();
      adapter.visitLabel(methodEnd);
     
      adapter.endMethod();
     
  }

  private Tag getComponent() throws BytecodeException {
    Iterator it = getStatements().iterator();
    Statement s;
    Tag t;
        while(it.hasNext()) {
          s=(Statement)it.next();
          if(s instanceof Tag) {
            t=(Tag)s;
            if(t.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Component"))return t;
          }
        }
    throw new BytecodeException("missing component",getStart());
  }
  private Tag getInterface() throws BytecodeException {
    Iterator it = getStatements().iterator();
    Statement s;
    Tag t;
        while(it.hasNext()) {
          s=(Statement)it.next();
          if(s instanceof Tag) {
            t=(Tag)s;
            if(t.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Interface"))return t;
          }
        }
    throw new BytecodeException("missing interface",getStart());
  }

  private void writeOutFunctionDefaultValueInnerInner(BytecodeContext bc, Function function) throws BytecodeException {
    GeneratorAdapter adapter = bc.getAdapter();
   
    List<Argument> args = function.getArguments();
   
    if(args.size()==0) {
      adapter.loadArg(DEFAULT_VALUE);
      adapter.returnValue();
      return;
    }
     
    Iterator<Argument> it = args.iterator();
    Argument arg;
    ConditionVisitor cv=new ConditionVisitor();
    DecisionIntVisitor div;
    cv.visitBefore();
    int count=0;
    while(it.hasNext()) {
      arg=it.next();
      cv.visitWhenBeforeExpr();
        div=new DecisionIntVisitor();
        div.visitBegin();
          adapter.loadArg(2);
        div.visitEQ();
          adapter.push(count++);
        div.visitEnd(bc);
      cv.visitWhenAfterExprBeforeBody(bc);
        Expression defaultValue = arg.getDefaultValue();
        if(defaultValue!=null) {
          /*if(defaultValue instanceof Null) {
            adapter.invokeStatic(NULL, GET_INSTANCE);
          }
          else*/
          defaultValue.writeOut(bc, Expression.MODE_REF);
        }
        else
          adapter.loadArg(DEFAULT_VALUE);
          //adapter.visitInsn(Opcodes.ACONST_NULL);
        adapter.returnValue();
      cv.visitWhenAfterBody(bc);
    }
    cv.visitOtherviseBeforeBody();
      //adapter.visitInsn(ACONST_NULL);
      //adapter.returnValue();
    cv.visitOtherviseAfterBody();
    cv.visitAfter(bc);
  }

  private Function[] getFunctions() {
    Function[] funcs=new Function[functions.size()];
    Iterator it = functions.iterator();
    int count=0;
    while(it.hasNext()) {
      funcs[count++]=(Function) it.next();
    }
    return funcs;
  }
 
  private TagThread[] getThreads() {
    TagThread[] threads=new TagThread[this.threads.size()];
    Iterator it = this.threads.iterator();
    int count=0;
    while(it.hasNext()) {
      threads[count++]=(TagThread) it.next();
    }
    return threads;
  }
 
 
  public void _writeOut(BytecodeContext bc) throws BytecodeException {
   
  }

  private void writeOutNewComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag component) throws BytecodeException {
   
    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_COMPONENT_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
        BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,NEW_COMPONENT_IMPL_INSTANCE,writeLog(),supressWSbeforeArg);
      Label methodBegin=new Label();
      Label methodEnd=new Label();
     
    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
      adapter.visitLabel(methodBegin);

      //ExpressionUtil.visitLine(adapter, component.getStartLine());
     
    int comp=adapter.newLocal(Types.COMPONENT_IMPL);
    adapter.newInstance(Types.COMPONENT_IMPL);
    adapter.dup();
   
    Attribute attr;
    // ComponentPage
    adapter.visitVarInsn(Opcodes.ALOAD, 0);
    adapter.checkCast(Types.COMPONENT_PAGE);

    // !!! also check CFMLScriptTransformer.addMetaData if you do any change here !!!
   
    // Output
    attr = component.removeAttribute("output");
    if(attr!=null) {
      ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    }
    else ASMConstants.NULL(adapter);

    // synchronized
    attr = component.removeAttribute("synchronized");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE);
    else adapter.push(false);

    // extends
    attr = component.removeAttribute("extends");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");
    // implements
    attr = component.removeAttribute("implements");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");
   
    // hint
    attr = component.removeAttribute("hint");
    if(attr!=null) {
      Expression value = attr.getValue();
      if(!(value instanceof Literal)){
        value=LitString.toExprString("[runtime expression]");
      }
      ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF);
    }
    else adapter.push("");
   
    // dspName
    attr = component.removeAttribute("displayname");
    if(attr==null) attr=component.getAttribute("display");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");
       
    // callpath
    adapter.visitVarInsn(Opcodes.ALOAD, 2);
    // realpath
    adapter.visitVarInsn(Opcodes.ILOAD, 3);
   

    // style
    attr = component.removeAttribute("style");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");

    // persistent
    attr = component.removeAttribute("persistent");
    boolean persistent=false;
    if(attr!=null) {
      persistent=ASMUtil.toBoolean(attr,component.getStart()).booleanValue();
    }
   
    // persistent
    attr = component.removeAttribute("accessors");
    boolean accessors=false;
    if(attr!=null) {
      accessors=ASMUtil.toBoolean(attr,component.getStart()).booleanValue();
    }

    adapter.push(persistent);
    adapter.push(accessors);
    //ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE);
   
    //adapter.visitVarInsn(Opcodes.ALOAD, 4);
    createMetaDataStruct(bc,component.getAttributes(),component.getMetaData());
   
    adapter.invokeConstructor(Types.COMPONENT_IMPL, CONSTR_COMPONENT_IMPL);
   
    adapter.storeLocal(comp);
   
    //Component Impl(ComponentPage componentPage,boolean output, String extend, String hint, String dspName)
   
   
    // initComponent(pc,c);
    adapter.visitVarInsn(Opcodes.ALOAD, 0);
    adapter.loadArg(0);
    adapter.loadLocal(comp);
    adapter.invokeVirtual(Types.COMPONENT_PAGE, INIT_COMPONENT);
   
        adapter.visitLabel(methodEnd);
       
        // return component;
        adapter.loadLocal(comp);

        adapter.returnValue();
      //ExpressionUtil.visitLine(adapter, component.getEndLine());
        adapter.endMethod();
   
       
  }
 
  private void writeOutNewInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag interf) throws BytecodeException {
    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_INTERFACE_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw);
        BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,NEW_INTERFACE_IMPL_INSTANCE,writeLog(),supressWSbeforeArg);
      Label methodBegin=new Label();
      Label methodEnd=new Label();

     
    adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
      adapter.visitLabel(methodBegin);

      //ExpressionUtil.visitLine(adapter, interf.getStartLine());
     
    int comp=adapter.newLocal(Types.INTERFACE_IMPL);
   
   
    adapter.newInstance(Types.INTERFACE_IMPL);
    adapter.dup();
   
   
    Attribute attr;
    // Interface Page
    adapter.visitVarInsn(Opcodes.ALOAD, 0);
    adapter.checkCast(Types.INTERFACE_PAGE);

    // extened
    attr = interf.removeAttribute("extends");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");
   
    // hint
    attr = interf.removeAttribute("hint");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");
   
    // dspName
    attr = interf.removeAttribute("displayname");
    if(attr==null) attr=interf.getAttribute("display");
    if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF);
    else adapter.push("");
   
   
    // callpath
    adapter.visitVarInsn(Opcodes.ALOAD, 1);
    // realpath
    adapter.visitVarInsn(Opcodes.ILOAD, 2);
   
    // interface udfs
    adapter.visitVarInsn(Opcodes.ALOAD, 3);
   
    createMetaDataStruct(bc,interf.getAttributes(),interf.getMetaData());
   
   
    adapter.invokeConstructor(Types.INTERFACE_IMPL, CONSTR_INTERFACE_IMPL);
   
    adapter.storeLocal(comp);
   
   
   
    // initInterface(pc,c);
    adapter.visitVarInsn(Opcodes.ALOAD, 0);
    //adapter.loadArg(0);
    adapter.loadLocal(comp);
    adapter.invokeVirtual(Types.INTERFACE_PAGE, INIT_INTERFACE);
   
    adapter.visitLabel(methodEnd);
       
       
        // return interface;
        adapter.loadLocal(comp);

        adapter.returnValue();
      //ExpressionUtil.visitLine(adapter, interf.getEndLine());
        adapter.endMethod();
   
       
  }
 
  public static boolean hasMetaDataStruct(Map attrs, Map meta) {
    if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){
      return false;
    }
    return true;
  }
 
  public static void createMetaDataStruct(BytecodeContext bc, Map attrs, Map meta) throws BytecodeException {
   
   
    GeneratorAdapter adapter = bc.getAdapter();
    if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){
      ASMConstants.NULL(bc.getAdapter());
      bc.getAdapter().cast(Types.OBJECT,STRUCT_IMPL);
      return;
    }
   
    int sct=adapter.newLocal(STRUCT_IMPL);
    adapter.newInstance(STRUCT_IMPL);
    adapter.dup();
    adapter.invokeConstructor(STRUCT_IMPL, INIT_STRUCT_IMPL);
    adapter.storeLocal(sct);
    if(meta!=null) {
      _createMetaDataStruct(bc,adapter,sct,meta);
    }
    if(attrs!=null) {
      _createMetaDataStruct(bc,adapter,sct,attrs);
    }
   
   
    adapter.loadLocal(sct);
  }

  private static void _createMetaDataStruct(BytecodeContext bc, GeneratorAdapter adapter, int sct, Map attrs) throws BytecodeException {
    Attribute attr;
    Iterator it = attrs.entrySet().iterator();
    Entry entry;
    while(it.hasNext()){
      entry = (Map.Entry)it.next();
      attr=(Attribute) entry.getValue();
      adapter.loadLocal(sct);
      adapter.push(attr.getName());
      if(attr.getValue() instanceof Literal)
        ExpressionUtil.writeOutSilent(attr.getValue(),bc,Expression.MODE_REF);
      else
        adapter.push("[runtime expression]");
     
      adapter.invokeVirtual(STRUCT_IMPL, SET_EL);
      adapter.pop();
    }
  }

  private void writeOutCall(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw) throws BytecodeException {
    //GeneratorAdapter adapter = bc.getAdapter();
    GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , CALL, null, new Type[]{Types.THROWABLE}, cw);
        Label methodBegin=new Label();
        Label methodEnd=new Label();
 
      adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0);
        adapter.visitLabel(methodBegin);

                  writeOutCallBody(new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,CALL,writeLog(),supressWSbeforeArg),this,IFunction.PAGE_TYPE_REGULAR);
         
          adapter.visitLabel(methodEnd);
          adapter.returnValue();
        adapter.endMethod();
    }


  private void writeOutCallBody(BytecodeContext bc,Body body, int pageType) throws BytecodeException {
    // Other
    List<IFunction> functions=new ArrayList<IFunction>();
    getFunctions(functions,bc,body,pageType);
   
    String className = Types.UDF_PROPERTIES_ARRAY.toString();
    //FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE , "udfs",className , null, null);
    //fv.visitEnd();
   
    BytecodeContext constr = bc.getConstructor();
    GeneratorAdapter cga = constr.getAdapter();
   
    cga.visitVarInsn(Opcodes.ALOAD, 0);
    cga.push(functions.size());
    //cga.visitTypeInsn(Opcodes.ANEWARRAY, Types.UDF_PROPERTIES.toString());
    cga.newArray(Types.UDF_PROPERTIES);
    cga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "udfs", className);
   
   
    Iterator<IFunction> it = functions.iterator();
    while(it.hasNext()){
      it.next().writeOut(bc, pageType);
    }
   
    if(pageType==IFunction.PAGE_TYPE_COMPONENT) {
      GeneratorAdapter adapter = bc.getAdapter();
      adapter.loadArg(1);
      adapter.loadArg(0);
      adapter.visitVarInsn(Opcodes.ALOAD, 0);
      adapter.invokeVirtual(Types.COMPONENT_IMPL, CHECK_INTERFACE);

    }
    if(pageType!=IFunction.PAGE_TYPE_INTERFACE){
      BodyBase.writeOut(bc.getStaticConstructor(),bc.getConstructor(),bc.getKeys(),body.getStatements(), bc);
    }
  }

  private static void getImports(List<String> list,Body body) throws BytecodeException {
    if(ASMUtil.isEmpty(body)) return;
    Statement stat;
    List stats = body.getStatements();
      int len=stats.size();
        for(int i=0;i<len;i++) {
          stat = (Statement)stats.get(i);
         
          // IFunction
          if(stat instanceof TagImport && !StringUtil.isEmpty(((TagImport)stat).getPath(),true)) {
            ImportDefintion id = ImportDefintionImpl.getInstance(((TagImport) stat).getPath(), null);
            if(id!=null && (!list.contains(id.toString()) && !list.contains(id.getPackage()+".*"))){
              list.add(id.toString());
            }
            stats.remove(i);
            len--;
            i--;
           
          }
          else if(stat instanceof HasBody) getImports(list, ((HasBody)stat).getBody());
          else if(stat instanceof HasBodies) {
            Body[] bodies=((HasBodies)stat).getBodies();
            for(int y=0;y<bodies.length;y++) {
              getImports(list,bodies[y]);
            }
          }
        }
  }
 
 
  private static void getFunctions(List<IFunction> functions,BytecodeContext bc, Body body, int pageType) throws BytecodeException {
    //writeOutImports(bc, body, pageType);
    if(ASMUtil.isEmpty(body)) return;
    Statement stat;
    List stats = body.getStatements();
      int len=stats.size();
        for(int i=0;i<len;i++) {
          stat = (Statement)stats.get(i);
         
          // IFunction
          if(stat instanceof IFunction) {
            functions.add((IFunction)stat);
            //((IFunction)stat).writeOut(bc,pageType);
            stats.remove(i);
            len--;
            i--;
          }
          else if(stat instanceof HasBody) getFunctions(functions,bc, ((HasBody)stat).getBody(), pageType);
          else if(stat instanceof HasBodies) {
            Body[] bodies=((HasBodies)stat).getBodies();
            for(int y=0;y<bodies.length;y++) {
              getFunctions(functions,bc,bodies[y] , pageType);
            }
           
          }
        }
  }


  /**
   * @return the source
   */
  public String getSource() {
    return path;
  }

  /**
   * @return if it is a component
   */
  public boolean isComponent() {
    return isComponent;
  }
 
  /**
   * set if the page is a component or not
   * @param cfc
   */
  public void setIsComponent(boolean isComponent) {
    this.isComponent = isComponent;
  }

  /**
   * @return if it is a component
   */
  public boolean isInterface() {
    return isInterface;
  }
 

  public boolean isPage() {
    return !isInterface && !isComponent;
  }
 
  /**
   * set if the page is a component or not
   * @param cfc
   */
  public void setIsInterface(boolean isInterface) {
    this.isInterface = isInterface;
  }
  /**
   * @return the lastModifed
   */
  public long getLastModifed() {
    return lastModifed;
  }


  public int[] addFunction(IFunction function) {
    int[] indexes=new int[2];
    Iterator<IFunction> it = functions.iterator();
    while(it.hasNext()){
      if(it.next() instanceof FunctionImpl)indexes[IFunction.ARRAY_INDEX]++;
    }
    indexes[IFunction.VALUE_INDEX]=functions.size();
   
    functions.add(function);
    return indexes;
  }
 
  public int addThread(TagThread thread) {
    threads.add(thread);
    return threads.size()-1;
  }

  public static byte[] setSourceLastModified(byte[] barr,  long lastModified) {
    ClassReader cr = new ClassReader(barr);
    ClassWriter cw = ASMUtil.getClassWriter();
    ClassVisitor ca = new SourceLastModifiedClassAdapter(cw,lastModified);
    cr.accept(ca, ClassReader.SKIP_DEBUG);
    return cw.toByteArray();
  }

  public Range registerString(BytecodeContext bc, String str) throws IOException {
    boolean append=true;
   
    if(staticTextLocation==null) {
      PageSource ps = bc.getPageSource();
      Mapping m = ps.getMapping();
      staticTextLocation=m.getClassRootDirectory();
     
      staticTextLocation.mkdirs();
      staticTextLocation=staticTextLocation.getRealResource(ps.getJavaName()+".txt");
      if(staticTextLocation.exists()) append=false;
      else staticTextLocation.createFile(true);
     
      off=0;
    }
   
   
    IOUtil.write(staticTextLocation, str, CharsetUtil.UTF8, append);
    Range r = new Range(off,str.length());
    off+=str.length();
    return r;
  }

  public int getMethodCount() {
    return ++methodCount;
  }

  public Config getConfig() {
    return config;
  }
 


}
  class SourceLastModifiedClassAdapter extends ClassVisitor {

    private long lastModified;
    public SourceLastModifiedClassAdapter(ClassWriter cw, long lastModified) {
      super(Opcodes.ASM4,cw);
      this.lastModified=lastModified;
    }
    public MethodVisitor visitMethod(int access,String name, String desc,  String signature, String[] exceptions) {
     
      if(!name.equals("getSourceLastModified"))return super.visitMethod(access,name, desc, signature, exceptions);
     
      MethodVisitor mv = cv.visitMethod(access,name, desc, signature, exceptions);
      mv.visitCode();
      mv.visitLdcInsn(Long.valueOf(lastModified));
      mv.visitInsn(Opcodes.LRETURN);
      mv.visitEnd();
      return mv;
    }

  }
TOP

Related Classes of railo.transformer.bytecode.SourceLastModifiedClassAdapter

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.