Package railo.transformer.bytecode.reflection

Source Code of railo.transformer.bytecode.reflection.ASMProxyFactory

package railo.transformer.bytecode.reflection;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections.map.ReferenceMap;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.commons.io.res.ResourceProvider;
import railo.commons.io.res.ResourcesImpl;
import railo.commons.io.res.util.ResourceUtil;
import railo.commons.lang.ClassUtil;
import railo.commons.lang.ExtendableClassLoader;
import railo.commons.lang.PhysicalClassLoader;
import railo.commons.lang.StringUtil;
import railo.runtime.PageContext;
import railo.runtime.functions.arrays.ArrayNew;
import railo.runtime.op.Caster;
import railo.runtime.type.util.ArrayUtil;
import railo.transformer.bytecode.util.ASMConstants;
import railo.transformer.bytecode.util.ASMUtil;
import railo.transformer.bytecode.util.Types;

public class ASMProxyFactory {

  public static final Type ASM_METHOD=Type.getType(ASMMethod.class);
  public static final Type CLASS404=Type.getType(ClassNotFoundException.class);
  public static final Type CLASS_UTIL=Type.getType(ClassUtil.class);
 
 
 
  //private static final org.objectweb.asm.commons.Method CONSTRUCTOR =
    //  new org.objectweb.asm.commons.Method("<init>",Types.VOID,new Type[]{Types.CLASS_LOADER,Types.CLASS});
  private static final org.objectweb.asm.commons.Method CONSTRUCTOR =
      new org.objectweb.asm.commons.Method("<init>",Types.VOID,new Type[]{Types.CLASS,Types.CLASS_ARRAY});

  private static final org.objectweb.asm.commons.Method LOAD_CLASS = new org.objectweb.asm.commons.Method(
      "loadClass",
      Types.CLASS,
      new Type[]{Types.STRING});
 

  // public static Class loadClass(String className, Class defaultValue) {
  private static final org.objectweb.asm.commons.Method LOAD_CLASS_EL = new org.objectweb.asm.commons.Method(
      "loadClass",
      Types.CLASS,
      new Type[]{Types.STRING,Types.CLASS});
 

  // public String getName();
  private static final org.objectweb.asm.commons.Method GET_NAME = new org.objectweb.asm.commons.Method(
      "getName",
      Types.STRING,
      new Type[]{});
 
  // public int getModifiers();
  private static final org.objectweb.asm.commons.Method GET_MODIFIERS = new org.objectweb.asm.commons.Method(
      "getModifiers",
      Types.INT_VALUE,
      new Type[]{});

  // public Class getReturnType();
  private static final org.objectweb.asm.commons.Method GET_RETURN_TYPE_AS_STRING = new org.objectweb.asm.commons.Method(
      "getReturnTypeAsString",
      Types.STRING,
      new Type[]{});

 
 
 
  private static final org.objectweb.asm.commons.Method INVOKE = new org.objectweb.asm.commons.Method(
      "invoke",
      Types.OBJECT,
      new Type[]{Types.OBJECT,Types.OBJECT_ARRAY});
 
 
  // primitive to reference type
  private static final org.objectweb.asm.commons.Method BOOL_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.BOOLEAN,new Type[]{Types.BOOLEAN_VALUE});
  private static final org.objectweb.asm.commons.Method SHORT_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.SHORT,new Type[]{Types.SHORT_VALUE});
  private static final org.objectweb.asm.commons.Method INT_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.INTEGER,new Type[]{Types.INT_VALUE});
  private static final org.objectweb.asm.commons.Method LONG_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.LONG,new Type[]{Types.LONG_VALUE});
  private static final org.objectweb.asm.commons.Method FLT_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.FLOAT,new Type[]{Types.FLOAT_VALUE});
  private static final org.objectweb.asm.commons.Method DBL_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.DOUBLE,new Type[]{Types.DOUBLE_VALUE});
  private static final org.objectweb.asm.commons.Method CHR_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.CHARACTER,new Type[]{Types.CHARACTER});
  private static final org.objectweb.asm.commons.Method BYT_VALUE_OF = new org.objectweb.asm.commons.Method("valueOf",Types.BYTE,new Type[]{Types.BYTE_VALUE});
 
  // reference type to primitive
  private static final org.objectweb.asm.commons.Method BOOL_VALUE = new org.objectweb.asm.commons.Method("booleanValue",Types.BOOLEAN_VALUE,new Type[]{});
  private static final org.objectweb.asm.commons.Method SHORT_VALUE = new org.objectweb.asm.commons.Method("shortValue",Types.SHORT_VALUE,new Type[]{});
  private static final org.objectweb.asm.commons.Method INT_VALUE = new org.objectweb.asm.commons.Method("intValue",Types.INT_VALUE,new Type[]{});
  private static final org.objectweb.asm.commons.Method LONG_VALUE = new org.objectweb.asm.commons.Method("longValue",Types.LONG_VALUE,new Type[]{});
  private static final org.objectweb.asm.commons.Method FLT_VALUE = new org.objectweb.asm.commons.Method("floatValue",Types.FLOAT_VALUE,new Type[]{});
  private static final org.objectweb.asm.commons.Method DBL_VALUE = new org.objectweb.asm.commons.Method("doubleValue",Types.DOUBLE_VALUE,new Type[]{});
  private static final org.objectweb.asm.commons.Method CHR_VALUE = new org.objectweb.asm.commons.Method("charValue",Types.CHAR,new Type[]{});
  private static final org.objectweb.asm.commons.Method BYT_VALUE = new org.objectweb.asm.commons.Method("byteValue",Types.BYTE_VALUE,new Type[]{});
 
  private static final org.objectweb.asm.commons.Method ASM_METHOD_CONSTRUCTOR = new org.objectweb.asm.commons.Method(
      "<init>",
      Types.VOID,
      new Type[]{Types.CLASS,Types.CLASS_ARRAY}
        );
 
 
  private static final Map<String,ASMMethod>methods=new ReferenceMap();

  public static void main(String[] args) throws Throwable {
    ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
    Resource root = frp.getResource("/Users/mic/Projects/Railo/webroot/WEB-INF/railo/cfclasses/wrappers/");
    root.mkdir();
    PhysicalClassLoader pcl = new PhysicalClassLoader(root);
    //PhysicalClassLoader pcl = (PhysicalClassLoader)ThreadLocalPageContext.getConfig().getRPCClassLoader(false);

    ASMProxyFactory.getClass(pcl, root, ArrayNew.class);
   
   
    ASMMethod method = ASMProxyFactory.getMethod(pcl, root, ArrayNew.class, "call", new Class[]{PageContext.class});
    //print.e(method.invoke(null, new Object[]{null}));
   
   
   
   
  }
 
  public static ASMClass getClass(ExtendableClassLoader pcl,Resource classRoot,Class clazz) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
    Type type = Type.getType(clazz);

      // Fields
      Field[] fields = clazz.getFields();
      for(int i=0;i<fields.length;i++){
        if(Modifier.isPrivate(fields[i].getModifiers())) continue;
        createField(type,fields[i]);
      }
     
      // Methods
      Method[] methods = clazz.getMethods();
      Map<String,ASMMethod> amethods=new HashMap<String, ASMMethod>();
      for(int i=0;i<methods.length;i++){
        if(Modifier.isPrivate(methods[i].getModifiers())) continue;
        amethods.put(methods[i].getName(), getMethod(pcl,classRoot,type,clazz,methods[i]));
      }
     
      return new ASMClass(clazz.getName(),amethods);
     
  }
 
  private static void createField(Type type, Field field) {
    // TODO Auto-generated method stub
   
  }

  public static ASMMethod getMethod(ExtendableClassLoader pcl, Resource classRoot, Class clazz, String methodName, Class[] parameters) throws IOException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
    String className = createMethodName(clazz,methodName,parameters);
   
    // check if already in memory cache
    ASMMethod asmm = methods.get(className);
    if(asmm!=null){
      //print.e("use loaded from memory");
      return asmm;
    }
   
    // try to load existing ASM Class
    Class<?> asmClass;
    try {
      asmClass = pcl.loadClass(className);
      //print.e("use existing class");
    }
    catch (ClassNotFoundException cnfe) {
      Type type = Type.getType(clazz);
      Method method = clazz.getMethod(methodName, parameters);
      byte[] barr = _createMethod(type, clazz, method, classRoot, className);
      asmClass=pcl.loadClass(className, barr);
      //print.e("create class");
    }
    asmm = newInstance(asmClass,clazz,parameters);
    //methods.put(className, asmm);
    return asmm;
  }

  private static ASMMethod getMethod(ExtendableClassLoader pcl, Resource classRoot, Type type,Class clazz, Method method) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException {
    String className = createMethodName(clazz,method.getName(),method.getParameterTypes());
   
    // check if already in memory cache
    ASMMethod asmm = methods.get(className);
    if(asmm!=null)return asmm;
   
    // try to load existing ASM Class
    Class<?> asmClass;
    try {
      asmClass = pcl.loadClass(className);
    }
    catch (ClassNotFoundException cnfe) {
      byte[] barr = _createMethod(type, clazz, method, classRoot, className);
      asmClass=pcl.loadClass(className, barr);
    }
   
    asmm = newInstance(asmClass,clazz,method.getParameterTypes());
    methods.put(className, asmm);
    return asmm;
  }

  private static ASMMethod newInstance(Class<?> asmClass, Class<?> decClass, Class[] params) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException {
    Constructor<ASMMethod> constr = (Constructor<ASMMethod>) asmClass.getConstructor(
        new Class[]{
          Class.class,
          Class[].class
        }
    );
    return constr.newInstance(new Object[]{
        decClass,
        params
      });
    
    //return (ASMMethod) asmClass.newInstance();
  }
 
 
  private static String createMethodName(Class clazz,String methodName,Class[] paramTypes) {
    StringBuilder sb = new StringBuilder("method.")
    .append(clazz.getName())
    .append(methodName);
   
    paramNames(sb,paramTypes);
   
    return sb.toString();
  }

  private static byte[] _createMethod(Type type,Class clazz, Method method,Resource classRoot, String className) throws IOException {
    Class<?> rtn = method.getReturnType();
      Type rtnType = Type.getType(rtn);
     
    className=className.replace('.',File.separatorChar);
    ClassWriter cw = ASMUtil.getClassWriter();
      cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, className, null, ASM_METHOD.getInternalName(), null);
   

// CONSTRUCTOR

      GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR,null,null,cw);
     
      Label begin = new Label();
        adapter.visitLabel(begin);
    adapter.loadThis();
       
      adapter.visitVarInsn(Opcodes.ALOAD, 1);
    adapter.visitVarInsn(Opcodes.ALOAD, 2);
       
    adapter.invokeConstructor(ASM_METHOD, CONSTRUCTOR);
    adapter.visitInsn(Opcodes.RETURN);
   
    Label end = new Label();
    adapter.visitLabel(end);
   
    adapter.endMethod();
   
  /*
  
      GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR,null,null,cw);
     
      Label begin = new Label();
        adapter.visitLabel(begin);
    adapter.loadThis();
       
      // clazz
        adapter.visitVarInsn(Opcodes.ALOAD, 2);
       
        // parameterTypes
        Class<?>[] params = method.getParameterTypes();
        Type[] paramTypes = new Type[params.length];
      ArrayVisitor av=new ArrayVisitor();
      av.visitBegin(adapter, Types.CLASS, params.length);
      for(int i=0;i<params.length;i++){
        paramTypes[i]=Type.getType(params[i]);
        av.visitBeginItem(adapter, i);
          loadClass(adapter,params[i]);
        av.visitEndItem(adapter);
      }
      av.visitEnd();
     
    adapter.invokeConstructor(ASM_METHOD, ASM_METHOD_CONSTRUCTOR);
    adapter.visitInsn(Opcodes.RETURN);
   
    Label end = new Label();
    adapter.visitLabel(end);
   
    adapter.endMethod();
   */
   
   
   
  // METHOD getName();
    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , GET_NAME, null, null, cw);
    adapter.push(method.getName());
    adapter.visitInsn(Opcodes.ARETURN);
        adapter.endMethod();
   
    // METHOD getModifiers();
    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , GET_MODIFIERS, null, null, cw);
    adapter.push(method.getModifiers());
    adapter.visitInsn(Opcodes.IRETURN);
        adapter.endMethod();
       

   
    // METHOD getReturnType();
        adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , GET_RETURN_TYPE_AS_STRING, null, null, cw);
   
    adapter.push(method.getReturnType().getName());
    adapter.visitInsn(Opcodes.ARETURN);
       
    adapter.endMethod();
       
   
       
       
  // METHOD INVOKE
    boolean isStatic = Modifier.isStatic(method.getModifiers());
    adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , INVOKE, null, null, cw);
        Label start=adapter.newLabel();
        adapter.visitLabel(start);
       
        // load Object
        if(!isStatic) {
          adapter.visitVarInsn(Opcodes.ALOAD, 1);
          adapter.checkCast(type);
    }
         
        // load params
        Class<?>[] params = method.getParameterTypes();

        Type[] paramTypes = new Type[params.length];
      for(int i=0;i<params.length;i++){
        paramTypes[i]=Type.getType(params[i]);
      }

        for(int i=0;i<params.length;i++){
          adapter.visitVarInsn(Opcodes.ALOAD, 2);
          adapter.push(i);
          //adapter.visitInsn(Opcodes.ICONST_0);
          adapter.visitInsn(Opcodes.AALOAD);
         
          adapter.checkCast(toReferenceType(params[i],paramTypes[i]));
         
          // cast
          if(params[i]==boolean.class) adapter.invokeVirtual(Types.BOOLEAN, BOOL_VALUE);
          else if(params[i]==short.class) adapter.invokeVirtual(Types.SHORT, SHORT_VALUE);
          else if(params[i]==int.class) adapter.invokeVirtual(Types.INTEGER, INT_VALUE);
          else if(params[i]==float.class) adapter.invokeVirtual(Types.FLOAT, FLT_VALUE);
          else if(params[i]==long.class) adapter.invokeVirtual(Types.LONG, LONG_VALUE);
          else if(params[i]==double.class) adapter.invokeVirtual(Types.DOUBLE, DBL_VALUE);
          else if(params[i]==char.class) adapter.invokeVirtual(Types.CHARACTER, CHR_VALUE);
          else if(params[i]==byte.class) adapter.invokeVirtual(Types.BYTE, BYT_VALUE);
          //else adapter.checkCast(paramTypes[i]);
         
        }
       
       
        // call method
      final org.objectweb.asm.commons.Method m = new org.objectweb.asm.commons.Method(method.getName(),rtnType,paramTypes);
      if(isStatic)adapter.invokeStatic(type, m);
      else adapter.invokeVirtual(type, m);
        
     
      // return
      if(rtn==void.class) ASMConstants.NULL(adapter);
     
     
      // cast result to object
      if(rtn==boolean.class) adapter.invokeStatic(Types.BOOLEAN, BOOL_VALUE_OF);
      else if(rtn==short.class) adapter.invokeStatic(Types.SHORT, SHORT_VALUE_OF);
      else if(rtn==int.class) adapter.invokeStatic(Types.INTEGER, INT_VALUE_OF);
      else if(rtn==long.class) adapter.invokeStatic(Types.LONG, LONG_VALUE_OF);
      else if(rtn==float.class) adapter.invokeStatic(Types.FLOAT, FLT_VALUE_OF);
      else if(rtn==double.class) adapter.invokeStatic(Types.DOUBLE, DBL_VALUE_OF);
      else if(rtn==char.class) adapter.invokeStatic(Types.CHARACTER, CHR_VALUE_OF);
      else if(rtn==byte.class) adapter.invokeStatic(Types.BYTE, BYT_VALUE_OF);
     
      adapter.visitInsn(Opcodes.ARETURN);
       
        adapter.endMethod();
   
       
   
        if(classRoot!=null) {
          Resource classFile=classRoot.getRealResource(className+".class");
          return store(cw.toByteArray(),classFile);
        }
        return cw.toByteArray();
  }
 

  private static Type toReferenceType(Class<?> clazz, Type defaultValue) {
    if(int.class==clazz) return Types.INTEGER;
    else if(long.class==clazz) return Types.LONG;
    else if(char.class==clazz) return Types.CHARACTER;
    else if(byte.class==clazz) return Types.BYTE;
    else if(float.class==clazz) return Types.FLOAT;
    else if(double.class==clazz) return Types.DOUBLE;
    else if(boolean.class==clazz) return Types.BOOLEAN;
    else if(short.class==clazz) return Types.SHORT;
    return defaultValue;
  }

  private static void loadClass(GeneratorAdapter adapter, Class<?> clazz) {
    if(void.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;");
   
    // primitive types
    else if(int.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
    else if(long.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
    else if(char.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
    else if(byte.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
    else if(float.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
    else if(double.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
    else if(boolean.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
    else if(short.class==clazz) adapter.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
   
    // TODO ref types
   
    else {
        adapter.visitVarInsn(Opcodes.ALOAD, 1);
          adapter.push(clazz.getName());
      adapter.invokeVirtual(Types.CLASS_LOADER,LOAD_CLASS );
    }
  }

  private static void paramNames(StringBuilder sb, Class<?>[] params) {
    if(ArrayUtil.isEmpty(params)) return;
   
    for(int i=0;i<params.length;i++){
      sb.append('$');
      if(params[i].isArray())
        sb.append(StringUtil.replace(Caster.toClassName(params[i]).replace('.', '_'),"[]","_arr",false));
      else
        sb.append(params[i].getName().replace('.', '_'));
    }
  }

  private static byte[] store(byte[] barr,Resource classFile) throws IOException {
    // create class file
        ResourceUtil.touch(classFile);
        //print.e(classFile);
        IOUtil.copy(new ByteArrayInputStream(barr), classFile,true);
       return barr;
  }
  /*private void store(ClassWriter cw) {
    // create class file
        byte[] barr = cw.toByteArray();
     
        try {
          ResourceUtil.touch(classFile);
          IOUtil.copy(new ByteArrayInputStream(barr), classFile,true);
         
          cl = (PhysicalClassLoader) mapping.getConfig().getRPCClassLoader(true);
          Class<?> clazz = cl.loadClass(className, barr);
          return newInstance(clazz, config,cfc);
        }
        catch(Throwable t) {
          throw Caster.toPageException(t);
        }
  }*/
 
TOP

Related Classes of railo.transformer.bytecode.reflection.ASMProxyFactory

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.