Search in sources :

Example 1 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.

the class ProxySubclassAdapter method processMethod.

private void processMethod(int access, String name, String desc, String signature, String[] exceptions) {
    LOGGER.debug(Constants.LOG_ENTRY, "processMethod", new Object[] { access, name, desc, signature, exceptions });
    LOGGER.debug("Processing method: {} with descriptor {}", name, desc);
    // identify the target method parameters and return type
    Method currentTransformMethod = new Method(name, desc);
    Type[] targetMethodParameters = currentTransformMethod.getArgumentTypes();
    Type returnType = currentTransformMethod.getReturnType();
    // we create a static field for each method we encounter with a name
    // like method_parm1_parm2...
    StringBuilder methodStaticFieldNameBuilder = new StringBuilder(name);
    // the dots first
    for (Type t : targetMethodParameters) {
        methodStaticFieldNameBuilder.append("_");
        methodStaticFieldNameBuilder.append(t.getClassName().replaceAll("\\[\\]", "Array").replaceAll("\\.", ""));
    }
    String methodStaticFieldName = methodStaticFieldNameBuilder.toString();
    // add a private static field for the method
    cv.visitField(ACC_PRIVATE | ACC_STATIC, methodStaticFieldName, METHOD_TYPE.getDescriptor(), null, null);
    // visit the method using the class writer, delegated through the method
    // visitor and generator
    // modify the method access so that any native methods aren't
    // described as native
    // since they won't be native in proxy form
    // also stop methods being marked synchronized on the proxy as they will
    // be sync
    // on the real object
    int newAccess = access & (~ACC_NATIVE) & (~ACC_SYNCHRONIZED);
    MethodVisitor mv = cv.visitMethod(newAccess, name, desc, signature, exceptions);
    // use a GeneratorAdapter to build the invoke call directly in byte code
    GeneratorAdapter methodAdapter = new GeneratorAdapter(mv, newAccess, name, desc);
    /*
     * Stage 1 creates the bytecode for adding the reflected method of the
     * superclass to a static field in the subclass: private static Method
     * methodName_parm1_parm2... = null; static{ methodName_parm1_parm2... =
     * superClass.getDeclaredMethod(methodName,new Class[]{method args}; }
     * 
     * Stage 2 is to call the ih.invoke(this,methodName_parm1_parm2,args) in
     * the new subclass methods Stage 3 is to cast the return value to the
     * correct type
     */
    /*
     * Stage 1 use superClass.getMethod(methodName,new Class[]{method args}
     * from the Class object on the stack
     */
    // load the static superclass Class onto the stack
    staticAdapter.getStatic(newClassType, currentClassFieldName, CLASS_TYPE);
    // push the method name string arg onto the stack
    staticAdapter.push(name);
    // create an array of the method parm class[] arg
    staticAdapter.push(targetMethodParameters.length);
    staticAdapter.newArray(CLASS_TYPE);
    int index = 0;
    for (Type t : targetMethodParameters) {
        staticAdapter.dup();
        staticAdapter.push(index);
        switch(t.getSort()) {
            case Type.BOOLEAN:
                staticAdapter.getStatic(Type.getType(java.lang.Boolean.class), "TYPE", CLASS_TYPE);
                break;
            case Type.BYTE:
                staticAdapter.getStatic(Type.getType(java.lang.Byte.class), "TYPE", CLASS_TYPE);
                break;
            case Type.CHAR:
                staticAdapter.getStatic(Type.getType(java.lang.Character.class), "TYPE", CLASS_TYPE);
                break;
            case Type.DOUBLE:
                staticAdapter.getStatic(Type.getType(java.lang.Double.class), "TYPE", CLASS_TYPE);
                break;
            case Type.FLOAT:
                staticAdapter.getStatic(Type.getType(java.lang.Float.class), "TYPE", CLASS_TYPE);
                break;
            case Type.INT:
                staticAdapter.getStatic(Type.getType(java.lang.Integer.class), "TYPE", CLASS_TYPE);
                break;
            case Type.LONG:
                staticAdapter.getStatic(Type.getType(java.lang.Long.class), "TYPE", CLASS_TYPE);
                break;
            case Type.SHORT:
                staticAdapter.getStatic(Type.getType(java.lang.Short.class), "TYPE", CLASS_TYPE);
                break;
            default:
            case Type.OBJECT:
                staticAdapter.push(t);
                break;
        }
        staticAdapter.arrayStore(CLASS_TYPE);
        index++;
    }
    // invoke the getMethod
    staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE, new Type[] { STRING_TYPE, Type.getType(java.lang.Class[].class) }));
    // store the reflected method in the static field
    staticAdapter.putStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
    /*
     * Stage 2 call the ih.invoke(this,supermethod,parms)
     */
    // load this to get the ih field
    methodAdapter.loadThis();
    // load the invocation handler from the field (the location of the
    // InvocationHandler.invoke)
    methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
    // loadThis (the first arg of the InvocationHandler.invoke)
    methodAdapter.loadThis();
    // load the method to invoke (the second arg of the
    // InvocationHandler.invoke)
    methodAdapter.getStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
    // load all the method arguments onto the stack as an object array (the
    // third arg of the InvocationHandler.invoke)
    methodAdapter.loadArgArray();
    // generate the invoke method
    Method invocationHandlerInvokeMethod = new Method("invoke", OBJECT_TYPE, new Type[] { OBJECT_TYPE, METHOD_TYPE, Type.getType(java.lang.Object[].class) });
    // call the invoke method of the invocation handler
    methodAdapter.invokeInterface(IH_TYPE, invocationHandlerInvokeMethod);
    /*
     * Stage 3 the returned object is now on the top of the stack We need to
     * check the type and cast as necessary
     */
    switch(returnType.getSort()) {
        case Type.BOOLEAN:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Boolean.class));
            methodAdapter.unbox(Type.BOOLEAN_TYPE);
            break;
        case Type.BYTE:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Byte.class));
            methodAdapter.unbox(Type.BYTE_TYPE);
            break;
        case Type.CHAR:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Character.class));
            methodAdapter.unbox(Type.CHAR_TYPE);
            break;
        case Type.DOUBLE:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Double.class));
            methodAdapter.unbox(Type.DOUBLE_TYPE);
            break;
        case Type.FLOAT:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Float.class));
            methodAdapter.unbox(Type.FLOAT_TYPE);
            break;
        case Type.INT:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Integer.class));
            methodAdapter.unbox(Type.INT_TYPE);
            break;
        case Type.LONG:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Long.class));
            methodAdapter.unbox(Type.LONG_TYPE);
            break;
        case Type.SHORT:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Short.class));
            methodAdapter.unbox(Type.SHORT_TYPE);
            break;
        case Type.VOID:
            methodAdapter.cast(OBJECT_TYPE, Type.getType(Void.class));
            methodAdapter.unbox(Type.VOID_TYPE);
            break;
        default:
        case Type.OBJECT:
            // in this case check the cast and cast the object to the return
            // type
            methodAdapter.checkCast(returnType);
            methodAdapter.cast(OBJECT_TYPE, returnType);
            break;
    }
    // return the (appropriately cast) result of the invocation from the
    // stack
    methodAdapter.returnValue();
    // end the method
    methodAdapter.endMethod();
    LOGGER.debug(Constants.LOG_EXIT, "processMethod");
}
Also used : Method(org.objectweb.asm.commons.Method) MethodVisitor(org.objectweb.asm.MethodVisitor) Type(org.objectweb.asm.Type) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter)

Example 2 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.

the class MethodCopyingClassAdapter method visitMethod.

@Override
public final MethodVisitor visitMethod(final int access, String name, String desc, String sig, String[] exceptions) {
    MethodVisitor mv = null;
    //abstract ones!.
    if (!!!name.equals("<init>") && !!!name.equals("<clinit>") && (access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_ABSTRACT | ACC_NATIVE | ACC_BRIDGE)) == 0) {
        // identify the target method parameters and return type
        Method currentTransformMethod = new Method(name, desc);
        // We don't want to duplicate a method we already overrode! 
        if (!!!knownMethods.add(currentTransformMethod))
            return null;
        // We can't override a final method
        if ((access & ACC_FINAL) != 0)
            throw new RuntimeException(new FinalModifierException(superToCopy, name));
        // package
        if ((access & (ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE)) == 0) {
            if (!!!samePackage) {
                methodHiddenException(name);
            }
        }
        //Safe to copy a call to this method!
        Type superType = Type.getType(superToCopy);
        // identify the target method parameters and return type
        String methodStaticFieldName = "methodField" + AbstractWovenProxyAdapter.getSanitizedUUIDString();
        transformedMethods.put(methodStaticFieldName, new TypeMethod(superType, currentTransformMethod));
        //Remember we need to copy the fake method *and* weave it, use a 
        //WovenProxyMethodAdapter as well as a CopyingMethodAdapter
        MethodVisitor weaver = wovenProxyAdapter.getWeavingMethodVisitor(access, name, desc, sig, exceptions, currentTransformMethod, methodStaticFieldName, superType, false);
        if (weaver instanceof AbstractWovenProxyMethodAdapter) {
            //gets around the problem, but if not the class will fail verification.
            if (!samePackage && (access & ACC_PROTECTED) != 0) {
                methodHiddenException(name);
            }
            mv = new CopyingMethodAdapter((GeneratorAdapter) weaver, superType, currentTransformMethod);
        } else {
            //For whatever reason we aren't weaving this method. The call to super.xxx() will always work
            mv = new CopyingMethodAdapter(new GeneratorAdapter(access, currentTransformMethod, mv), superType, currentTransformMethod);
        }
    }
    return mv;
}
Also used : Type(org.objectweb.asm.Type) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) FinalModifierException(org.apache.aries.proxy.FinalModifierException) Method(org.objectweb.asm.commons.Method) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 3 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.

the class AbstractWovenProxyAdapter method writeFinalWovenProxyMethods.

/**
   * Write the methods we need for wovenProxies on the highest supertype
   */
private final void writeFinalWovenProxyMethods() {
    // add private fields for the Callable<Object> dispatcher
    // and InvocationListener. These aren't static because we can have
    // multiple instances of the same proxy class. These should not be
    // serialized, or used in JPA or any other thing we can think of,
    // so we annotate them as necessary
    generateField(DISPATCHER_FIELD, Type.getDescriptor(Callable.class));
    generateField(LISTENER_FIELD, Type.getDescriptor(InvocationListener.class));
    // a general methodAdapter field that we will use to with GeneratorAdapters
    // to create the methods required to implement WovenProxy
    GeneratorAdapter methodAdapter;
    // add a method for unwrapping the dispatcher
    methodAdapter = getMethodGenerator(PUBLIC_GENERATED_METHOD_ACCESS, new Method("org_apache_aries_proxy_weaving_WovenProxy_unwrap", DISPATCHER_TYPE, NO_ARGS));
    // /////////////////////////////////////////////////////
    // Implement the method
    // load this to get the field
    methodAdapter.loadThis();
    // get the dispatcher field and return
    methodAdapter.getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
    methodAdapter.returnValue();
    methodAdapter.endMethod();
    // /////////////////////////////////////////////////////
    // add a method for checking if the dispatcher is set
    methodAdapter = getMethodGenerator(PUBLIC_GENERATED_METHOD_ACCESS, new Method("org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance", Type.BOOLEAN_TYPE, NO_ARGS));
    // /////////////////////////////////////////////////////
    // Implement the method
    // load this to get the field
    methodAdapter.loadThis();
    // make a label for return true
    Label returnTrueLabel = methodAdapter.newLabel();
    // get the dispatcher field for the stack
    methodAdapter.getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
    // check if the dispatcher was non-null and goto return true if it was
    methodAdapter.ifNonNull(returnTrueLabel);
    methodAdapter.loadThis();
    // get the listener field for the stack
    methodAdapter.getField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
    // check if the listener field was non-null and goto return true if it was
    methodAdapter.ifNonNull(returnTrueLabel);
    // return false if we haven't jumped anywhere
    methodAdapter.push(false);
    methodAdapter.returnValue();
    // mark the returnTrueLable
    methodAdapter.mark(returnTrueLabel);
    methodAdapter.push(true);
    methodAdapter.returnValue();
    // end the method
    methodAdapter.endMethod();
// ///////////////////////////////////////////////////////
}
Also used : InvocationListener(org.apache.aries.proxy.InvocationListener) Label(org.objectweb.asm.Label) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method) Callable(java.util.concurrent.Callable)

Example 4 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.

the class AbstractWovenProxyAdapter method getMethodGenerator.

/**
   * Get a generator for a method, this be annotated with the "invisibility"
   * annotations (and ensured synthetic)
   * 
   * @param methodSignature
   * @return
   */
private final GeneratorAdapter getMethodGenerator(int access, Method method) {
    access = access | ACC_SYNTHETIC;
    GeneratorAdapter ga = new GeneratorAdapter(access, method, null, null, cv);
    for (String s : annotationTypeDescriptors) ga.visitAnnotation(s, true).visitEnd();
    ga.visitCode();
    return ga;
}
Also used : GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter)

Example 5 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.

the class TCCLSetterVisitor method visitEnd.

@Override
public void visitEnd() {
    if (!woven) {
        // if this class wasn't woven, then don't add the synthesized method either.
        super.visitEnd();
        return;
    }
    // Add generated static method
    Set<String> methodNames = new HashSet<String>();
    for (WeavingData wd : weavingData) {
        /* Equivalent to:
             * private static void $$FCCL$$<className>$<methodName>(Class<?> cls) {
             *   Util.fixContextClassLoader("java.util.ServiceLoader", "load", cls, WovenClass.class.getClassLoader());
             * }
             */
        String methodName = getGeneratedMethodName(wd);
        if (methodNames.contains(methodName))
            continue;
        methodNames.add(methodName);
        Method method = new Method(methodName, Type.VOID_TYPE, new Type[] { CLASS_TYPE });
        GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(ACC_PRIVATE + ACC_STATIC, methodName, method.getDescriptor(), null, null), ACC_PRIVATE + ACC_STATIC, methodName, method.getDescriptor());
        //Load the strings, method parameter and target
        mv.visitLdcInsn(wd.getClassName());
        mv.visitLdcInsn(wd.getMethodName());
        mv.loadArg(0);
        mv.visitLdcInsn(targetClass);
        //Change the class on the stack into a classloader
        mv.invokeVirtual(CLASS_TYPE, new Method("getClassLoader", CLASSLOADER_TYPE, new Type[0]));
        //Call our util method
        mv.invokeStatic(UTIL_CLASS, new Method("fixContextClassloader", Type.VOID_TYPE, new Type[] { String_TYPE, String_TYPE, CLASS_TYPE, CLASSLOADER_TYPE }));
        mv.returnValue();
        mv.endMethod();
    }
    super.visitEnd();
}
Also used : Type(org.objectweb.asm.Type) WeavingData(org.apache.aries.spifly.WeavingData) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method) HashSet(java.util.HashSet)

Aggregations

GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)33 Method (org.objectweb.asm.commons.Method)24 Type (org.objectweb.asm.Type)14 Label (org.objectweb.asm.Label)8 ClassWriter (org.objectweb.asm.ClassWriter)7 MethodVisitor (org.objectweb.asm.MethodVisitor)7 IOException (java.io.IOException)5 ClassReader (org.objectweb.asm.ClassReader)5 ClassVisitor (org.objectweb.asm.ClassVisitor)4 Schema (co.cask.cdap.api.data.schema.Schema)3 TypeToken (com.google.common.reflect.TypeToken)2 InvocationHandler (java.lang.reflect.InvocationHandler)2 ArrayList (java.util.ArrayList)2 Set (java.util.Set)2 SchemaHash (co.cask.cdap.api.data.schema.SchemaHash)1 MetricsContext (co.cask.cdap.api.metrics.MetricsContext)1 Encoder (co.cask.cdap.common.io.Encoder)1 Throwables (com.google.common.base.Throwables)1 Sets (com.google.common.collect.Sets)1 File (java.io.File)1