Search in sources :

Example 21 with GeneratorAdapter

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

the class AbstractWovenProxyAdapter method writeCreateNewProxyInstanceAndConstructor.

/**
   * We write createNewProxyInstance separately because it isn't final, and is
   * overridden on each class, we also write a constructor for this method to
   * use if we don't have one.
   */
private final void writeCreateNewProxyInstanceAndConstructor() {
    GeneratorAdapter methodAdapter = getMethodGenerator(ACC_PUBLIC, new Method("org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance", WOVEN_PROXY_IFACE_TYPE, DISPATCHER_LISTENER_METHOD_ARGS));
    // /////////////////////////////////////////////////////
    // Implement the method
    // Create and instantiate a new instance, then return it
    methodAdapter.newInstance(typeBeingWoven);
    methodAdapter.dup();
    methodAdapter.loadArgs();
    methodAdapter.invokeConstructor(typeBeingWoven, new Method("<init>", Type.VOID_TYPE, DISPATCHER_LISTENER_METHOD_ARGS));
    methodAdapter.returnValue();
    methodAdapter.endMethod();
    //////////////////////////////////////////////////////////
    // Write a protected no-args constructor for this class
    methodAdapter = getMethodGenerator(ACC_PROTECTED | ACC_SYNTHETIC, ARGS_CONSTRUCTOR);
    if (implementWovenProxy) {
        methodAdapter.loadThis();
        if (superHasNoArgsConstructor)
            methodAdapter.invokeConstructor(superType, NO_ARGS_CONSTRUCTOR);
        else {
            if (hasNoArgsConstructor)
                methodAdapter.invokeConstructor(typeBeingWoven, NO_ARGS_CONSTRUCTOR);
            else
                throw new RuntimeException(new UnableToProxyException(typeBeingWoven.getClassName(), String.format("The class %s and its superclass %s do not have no-args constructors and cannot be woven.", typeBeingWoven.getClassName(), superType.getClassName())));
        }
        methodAdapter.loadThis();
        methodAdapter.loadArg(0);
        methodAdapter.putField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
        methodAdapter.loadThis();
        methodAdapter.loadArg(1);
        methodAdapter.putField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
    } else {
        //We just invoke the super with args
        methodAdapter.loadThis();
        methodAdapter.loadArgs();
        methodAdapter.invokeConstructor(superType, ARGS_CONSTRUCTOR);
    }
    //Throw an NPE if the dispatcher is null, return otherwise
    methodAdapter.loadArg(0);
    Label returnValue = methodAdapter.newLabel();
    methodAdapter.ifNonNull(returnValue);
    methodAdapter.newInstance(NPE_TYPE);
    methodAdapter.dup();
    methodAdapter.push("The dispatcher must never be null!");
    methodAdapter.invokeConstructor(NPE_TYPE, NPE_CONSTRUCTOR);
    methodAdapter.throwException();
    methodAdapter.mark(returnValue);
    methodAdapter.returnValue();
    methodAdapter.endMethod();
//////////////////////////////////////////////////////////
}
Also used : Label(org.objectweb.asm.Label) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) UnableToProxyException(org.apache.aries.proxy.UnableToProxyException) Method(org.objectweb.asm.commons.Method)

Example 22 with GeneratorAdapter

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

the class ProxySubclassAdapter method visit.

/*
   * This method visits the class to generate the new subclass.
   * 
   * The following things happen here: 1. The class is renamed to a dynamic
   * name 2. The existing class name is changed to be the superclass name so
   * that the generated class extends the original class. 3. A private field
   * is added to store an invocation handler 4. A constructor is added that
   * takes an invocation handler as an argument 5. The constructor method
   * instantiates an instance of the superclass 6. The constructor method sets
   * the invocation handler so the invoke method can be called from all the
   * subsequently rewritten methods 7. Add a getInvocationHandler() method 8.
   * store a static Class object of the superclass so we can reflectively find
   * methods later
   */
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    LOGGER.debug(Constants.LOG_ENTRY, "visit", new Object[] { version, access, name, signature, superName, interfaces });
    // store the superclass binary name
    this.superclassBinaryName = name.replaceAll("/", "\\.");
    try {
        this.superclassClass = Class.forName(superclassBinaryName, false, loader);
    } catch (ClassNotFoundException cnfe) {
        throw new TypeNotPresentException(superclassBinaryName, cnfe);
    }
    // from the superclass anyway
    if ((access & ACC_ABSTRACT) != 0) {
        //If the super was abstract the subclass should not be!
        access &= ~ACC_ABSTRACT;
    }
    cv.visit(ProxyUtils.getWeavingJavaVersion(), access, newClassName, signature, name, null);
    // add a private field for the invocation handler
    // this isn't static in case we have multiple instances of the same
    // proxy
    cv.visitField(ACC_PRIVATE, IH_FIELD, Type.getDescriptor(InvocationHandler.class), null, null);
    // create a static adapter for generating a static initialiser method in
    // the generated subclass
    staticAdapter = new GeneratorAdapter(ACC_STATIC, new Method("<clinit>", Type.VOID_TYPE, NO_ARGS), null, null, cv);
    // add a zero args constructor method
    Method m = new Method("<init>", Type.VOID_TYPE, NO_ARGS);
    GeneratorAdapter methodAdapter = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cv);
    // loadthis
    methodAdapter.loadThis();
    // List the constructors in the superclass.
    Constructor<?>[] constructors = superclassClass.getDeclaredConstructors();
    // Check that we've got at least one constructor, and get the 1st one in the list.
    if (constructors.length > 0) {
        // We now need to construct the proxy class as though it is going to invoke the superclasses constructor.
        // We do this because we can no longer call the java.lang.Object() zero arg constructor as the JVM now throws a VerifyError.
        // So what we do is build up the calling of the superclasses constructor using nulls and default values. This means that the 
        // class bytes can be verified by the JVM, and then in the ProxySubclassGenerator, we load the class without invoking the 
        // constructor. 
        Method constructor = Method.getMethod(constructors[0]);
        Type[] argTypes = constructor.getArgumentTypes();
        if (argTypes.length == 0) {
            methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>", Type.VOID_TYPE, NO_ARGS));
        } else {
            for (Type type : argTypes) {
                switch(type.getSort()) {
                    case Type.ARRAY:
                        // We need to process any array or multidimentional arrays.
                        String elementDesc = type.getElementType().getDescriptor();
                        String typeDesc = type.getDescriptor();
                        // Iterate over the number of arrays and load 0 for each one. Keep a count of the number of 
                        // arrays as we will need to run different code fo multi dimentional arrays.
                        int index = 0;
                        while (!elementDesc.equals(typeDesc)) {
                            typeDesc = typeDesc.substring(1);
                            methodAdapter.visitInsn(Opcodes.ICONST_0);
                            index++;
                        }
                        // If we're just a single array, then call the newArray method, otherwise use the MultiANewArray instruction.
                        if (index == 1) {
                            methodAdapter.newArray(type.getElementType());
                        } else {
                            methodAdapter.visitMultiANewArrayInsn(type.getDescriptor(), index);
                        }
                        break;
                    case Type.BOOLEAN:
                        methodAdapter.push(true);
                        break;
                    case Type.BYTE:
                        methodAdapter.push(Type.VOID_TYPE);
                        break;
                    case Type.CHAR:
                        methodAdapter.push(Type.VOID_TYPE);
                        break;
                    case Type.DOUBLE:
                        methodAdapter.push(0.0);
                        break;
                    case Type.FLOAT:
                        methodAdapter.push(0.0f);
                        break;
                    case Type.INT:
                        methodAdapter.push(0);
                        break;
                    case Type.LONG:
                        methodAdapter.push(0l);
                        break;
                    case Type.SHORT:
                        methodAdapter.push(0);
                        break;
                    default:
                    case Type.OBJECT:
                        methodAdapter.visitInsn(Opcodes.ACONST_NULL);
                        break;
                }
            }
            methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>", Type.VOID_TYPE, argTypes));
        }
    }
    methodAdapter.returnValue();
    methodAdapter.endMethod();
    // add a method for getting the invocation handler
    Method setter = new Method("setInvocationHandler", Type.VOID_TYPE, new Type[] { IH_TYPE });
    m = new Method("getInvocationHandler", IH_TYPE, NO_ARGS);
    methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, m, null, null, cv);
    // load this to get the field
    methodAdapter.loadThis();
    // get the ih field and return
    methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
    methodAdapter.returnValue();
    methodAdapter.endMethod();
    // add a method for setting the invocation handler
    methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, setter, null, null, cv);
    // load this to put the field
    methodAdapter.loadThis();
    // load the method arguments (i.e. the invocation handler) to the stack
    methodAdapter.loadArgs();
    // set the ih field using the method argument
    methodAdapter.putField(newClassType, IH_FIELD, IH_TYPE);
    methodAdapter.returnValue();
    methodAdapter.endMethod();
    // loop through the class hierarchy to get any needed methods off the
    // supertypes
    // start by finding the methods declared on the class of interest (the
    // superclass of our dynamic subclass)
    java.lang.reflect.Method[] observedMethods = superclassClass.getDeclaredMethods();
    // add the methods to a set of observedMethods
    ProxySubclassMethodHashSet<String> setOfObservedMethods = new ProxySubclassMethodHashSet<String>(observedMethods.length);
    setOfObservedMethods.addMethodArray(observedMethods);
    // get the next superclass in the hierarchy
    Class<?> nextSuperClass = superclassClass.getSuperclass();
    while (nextSuperClass != null) {
        // set the fields for the current class
        setCurrentAnalysisClassFields(nextSuperClass);
        // add a static field and static initializer code to the generated
        // subclass
        // for each of the superclasses in the hierarchy
        addClassStaticField(currentlyAnalysedClassName);
        LOGGER.debug("Class currently being analysed: {} {}", currentlyAnalysedClassName, currentlyAnalysedClass);
        // now find the methods declared on the current class and add them
        // to a set of foundMethods
        java.lang.reflect.Method[] foundMethods = currentlyAnalysedClass.getDeclaredMethods();
        ProxySubclassMethodHashSet<String> setOfFoundMethods = new ProxySubclassMethodHashSet<String>(foundMethods.length);
        setOfFoundMethods.addMethodArray(foundMethods);
        // remove from the set of foundMethods any methods we saw on a
        // subclass
        // because we want to use the lowest level declaration of a method
        setOfFoundMethods.removeAll(setOfObservedMethods);
        try {
            // read the current class and use a
            // ProxySubclassHierarchyAdapter
            // to process only methods on that class that are in the list
            ClassLoader loader = currentlyAnalysedClass.getClassLoader();
            if (loader == null) {
                loader = this.loader;
            }
            InputStream is = loader.getResourceAsStream(currentlyAnalysedClass.getName().replaceAll("\\.", "/") + ".class");
            if (is == null) {
                //use SystemModuleClassLoader as fallback
                ClassLoader classLoader = new SystemModuleClassLoader();
                is = classLoader.getResourceAsStream(currentlyAnalysedClass.getName().replaceAll("\\.", "/") + ".class");
            }
            ClassReader cr = new ClassReader(is);
            ClassVisitor hierarchyAdapter = new ProxySubclassHierarchyAdapter(this, setOfFoundMethods);
            cr.accept(hierarchyAdapter, ClassReader.SKIP_DEBUG);
        } catch (IOException e) {
            throw new TypeNotPresentException(currentlyAnalysedClassName, e);
        }
        // now add the foundMethods to the overall list of observed methods
        setOfObservedMethods.addAll(setOfFoundMethods);
        // get the next class up in the hierarchy and go again
        nextSuperClass = currentlyAnalysedClass.getSuperclass();
    }
    // we've finished looking at the superclass hierarchy
    // set the fields for the immediate superclass of our dynamic subclass
    setCurrentAnalysisClassFields(superclassClass);
    // add the class static field
    addClassStaticField(currentlyAnalysedClassName);
    // we do the lowest class last because we are already visiting the class
    // when in this adapter code
    // now we are ready to visit all the methods on the lowest class
    // which will happen by the ASM ClassVisitor implemented in this adapter
    LOGGER.debug(Constants.LOG_EXIT, "visit");
}
Also used : Constructor(java.lang.reflect.Constructor) InputStream(java.io.InputStream) Method(org.objectweb.asm.commons.Method) ClassVisitor(org.objectweb.asm.ClassVisitor) IOException(java.io.IOException) InvocationHandler(java.lang.reflect.InvocationHandler) Type(org.objectweb.asm.Type) SystemModuleClassLoader(org.apache.aries.proxy.impl.SystemModuleClassLoader) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) SystemModuleClassLoader(org.apache.aries.proxy.impl.SystemModuleClassLoader) ClassReader(org.objectweb.asm.ClassReader)

Example 23 with GeneratorAdapter

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

the class AsmProxyClassGenerator method defineSuperAccessorMethod.

private static void defineSuperAccessorMethod(ClassWriter cw, java.lang.reflect.Method method, Type superType, String superAccessorMethodSuffix) {
    Method originalAsmMethod = Method.getMethod(method);
    Method newAsmMethod = new Method(method.getName() + superAccessorMethodSuffix, originalAsmMethod.getReturnType(), originalAsmMethod.getArgumentTypes());
    GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, newAsmMethod, null, null, cw);
    mg.visitCode();
    // call super method
    mg.loadThis();
    mg.loadArgs();
    mg.visitMethodInsn(Opcodes.INVOKESPECIAL, superType.getInternalName(), method.getName(), Type.getMethodDescriptor(method), false);
    mg.returnValue();
    // finish the method
    mg.endMethod();
    mg.visitMaxs(10, 10);
    mg.visitEnd();
}
Also used : GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method)

Example 24 with GeneratorAdapter

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

the class AsmProxyClassGenerator method defineMethod.

private static void defineMethod(ClassWriter cw, java.lang.reflect.Method method, Class manualInvocationHandlerClass) {
    Type methodType = Type.getType(method);
    ArrayList<Type> exceptionsToCatch = new ArrayList<Type>();
    for (Class<?> exception : method.getExceptionTypes()) {
        if (!RuntimeException.class.isAssignableFrom(exception)) {
            exceptionsToCatch.add(Type.getType(exception));
        }
    }
    // push the method definition
    int modifiers = (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED) & method.getModifiers();
    Method asmMethod = Method.getMethod(method);
    GeneratorAdapter mg = new GeneratorAdapter(modifiers, asmMethod, null, getTypes(method.getExceptionTypes()), cw);
    // copy annotations
    for (Annotation annotation : method.getDeclaredAnnotations()) {
        mg.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true).visitEnd();
    }
    mg.visitCode();
    Label tryBlockStart = mg.mark();
    mg.loadThis();
    loadCurrentMethod(mg, method, methodType);
    loadArguments(mg, method, methodType);
    // invoke our ProxyInvocationHandler
    mg.invokeStatic(Type.getType(manualInvocationHandlerClass), Method.getMethod("Object staticInvoke(Object, java.lang.reflect.Method, Object[])"));
    // cast the result
    mg.unbox(methodType.getReturnType());
    // build try catch
    Label tryBlockEnd = mg.mark();
    // push return
    mg.returnValue();
    // catch runtime exceptions and rethrow it
    Label rethrow = mg.mark();
    mg.visitVarInsn(Opcodes.ASTORE, 1);
    mg.visitVarInsn(Opcodes.ALOAD, 1);
    mg.throwException();
    mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrow, Type.getInternalName(RuntimeException.class));
    // catch checked exceptions and rethrow it
    boolean throwableCatched = false;
    if (!exceptionsToCatch.isEmpty()) {
        rethrow = mg.mark();
        mg.visitVarInsn(Opcodes.ASTORE, 1);
        mg.visitVarInsn(Opcodes.ALOAD, 1);
        mg.throwException();
        // catch declared exceptions and rethrow it...
        for (Type exceptionType : exceptionsToCatch) {
            if (exceptionType.getClassName().equals(Throwable.class.getName())) {
                throwableCatched = true;
            }
            mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrow, exceptionType.getInternalName());
        }
    }
    // if throwable isn't alreached cachted, catch it and wrap it with an UndeclaredThrowableException and throw it
    if (!throwableCatched) {
        Type uteType = Type.getType(UndeclaredThrowableException.class);
        Label wrapAndRethrow = mg.mark();
        mg.visitVarInsn(Opcodes.ASTORE, 1);
        mg.newInstance(uteType);
        mg.dup();
        mg.visitVarInsn(Opcodes.ALOAD, 1);
        mg.invokeConstructor(uteType, Method.getMethod("void <init>(java.lang.Throwable)"));
        mg.throwException();
        mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, wrapAndRethrow, Type.getInternalName(Throwable.class));
    }
    // finish the method
    mg.endMethod();
    mg.visitMaxs(10, 10);
    mg.visitEnd();
}
Also used : Type(org.objectweb.asm.Type) ArrayList(java.util.ArrayList) Label(org.objectweb.asm.Label) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method) Annotation(java.lang.annotation.Annotation)

Example 25 with GeneratorAdapter

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

the class AsmProxyClassGenerator method defineDelegateInvocationHandlerConstructor.

private static void defineDelegateInvocationHandlerConstructor(ClassWriter cw, Type proxyType, Type superType, Type delegateInvocationHandlerType) {
    GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, new Method("<init>", Type.VOID_TYPE, new Type[] { delegateInvocationHandlerType }), null, null, cw);
    mg.visitCode();
    // invoke super constructor
    mg.loadThis();
    mg.invokeConstructor(superType, Method.getMethod("void <init> ()"));
    // set invocation handler
    mg.loadThis();
    mg.loadArg(0);
    mg.putField(proxyType, FIELDNAME_DELEGATE_INVOCATION_HANDLER, delegateInvocationHandlerType);
    mg.returnValue();
    mg.endMethod();
    mg.visitEnd();
}
Also used : Type(org.objectweb.asm.Type) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method)

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