Search in sources :

Example 21 with Method

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

the class AbstractWovenProxyAdapter method writeStaticInitMethod.

/**
   * Create fields and an initialiser for {@link java.lang.reflect.Method}
   * objects in our class
   */
private final void writeStaticInitMethod() {
    for (String methodStaticFieldName : transformedMethods.keySet()) {
        // add a private static field for the method
        cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, methodStaticFieldName, METHOD_TYPE.getDescriptor(), null, null).visitEnd();
    }
    GeneratorAdapter staticAdapter = new GeneratorAdapter(staticInitMethodFlags, staticInitMethod, null, null, cv);
    for (Entry<String, TypeMethod> entry : transformedMethods.entrySet()) {
        // Add some more code to the static initializer
        TypeMethod m = entry.getValue();
        Type[] targetMethodParameters = m.method.getArgumentTypes();
        String methodStaticFieldName = entry.getKey();
        Label beginPopulate = staticAdapter.newLabel();
        Label endPopulate = staticAdapter.newLabel();
        Label catchHandler = staticAdapter.newLabel();
        staticAdapter.visitTryCatchBlock(beginPopulate, endPopulate, catchHandler, THROWABLE_INAME);
        staticAdapter.mark(beginPopulate);
        staticAdapter.push(m.declaringClass);
        // push the method name string arg onto the stack
        staticAdapter.push(m.method.getName());
        // 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);
            staticAdapter.push(t);
            staticAdapter.arrayStore(CLASS_TYPE);
            index++;
        }
        // invoke the getMethod
        staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE, new Type[] { STRING_TYPE, CLASS_ARRAY_TYPE }));
        // store the reflected method in the static field
        staticAdapter.putStatic(typeBeingWoven, methodStaticFieldName, METHOD_TYPE);
        Label afterCatch = staticAdapter.newLabel();
        staticAdapter.mark(endPopulate);
        staticAdapter.goTo(afterCatch);
        staticAdapter.mark(catchHandler);
        // We don't care about the exception, so pop it off
        staticAdapter.pop();
        // store the reflected method in the static field
        staticAdapter.visitInsn(ACONST_NULL);
        staticAdapter.putStatic(typeBeingWoven, methodStaticFieldName, METHOD_TYPE);
        staticAdapter.mark(afterCatch);
    }
    staticAdapter.returnValue();
    staticAdapter.endMethod();
}
Also used : Type(org.objectweb.asm.Type) Label(org.objectweb.asm.Label) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method)

Example 22 with Method

use of org.objectweb.asm.commons.Method 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 23 with Method

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

the class AbstractWovenProxyAdapter method visitMethod.

/**
   * This method is called on each method implemented on this object (but not
   * for superclass methods) Each of these methods is visited in turn and the
   * code here generates the byte code for the calls to the InovcationListener
   * around the existing method
   */
public final MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    LOGGER.debug(Constants.LOG_ENTRY, "visitMethod", new Object[] { access, name, desc, signature, exceptions });
    Method currentMethod = new Method(name, desc);
    getKnownMethods().add(currentMethod);
    MethodVisitor methodVisitorToReturn = null;
    // compiler generated ones.
    if ((access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_NATIVE | ACC_BRIDGE)) == 0 && !!!name.equals("<init>") && !!!name.equals("<clinit>")) {
        // found a method we should weave
        //Create a field name and store it for later
        String methodStaticFieldName = "methodField" + getSanitizedUUIDString();
        transformedMethods.put(methodStaticFieldName, new TypeMethod(currentMethodDeclaringType, currentMethod));
        // Surround the MethodVisitor with our weaver so we can manipulate the code
        methodVisitorToReturn = getWeavingMethodVisitor(access, name, desc, signature, exceptions, currentMethod, methodStaticFieldName, currentMethodDeclaringType, currentMethodDeclaringTypeIsInterface);
    } else if (name.equals("<clinit>")) {
        //there is an existing clinit method, change the fields we use
        //to write our init code to static_init_UUID instead
        staticInitMethod = new Method("static_init_" + UU_ID, Type.VOID_TYPE, NO_ARGS);
        staticInitMethodFlags = staticInitMethodFlags | ACC_FINAL;
        methodVisitorToReturn = new AdviceAdapter(Opcodes.ASM5, cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc) {

            @Override
            protected void onMethodEnter() {
                //add into the <clinit> a call to our synthetic static_init_UUID
                invokeStatic(typeBeingWoven, staticInitMethod);
                super.onMethodEnter();
            }
        };
    } else {
        if (currentMethod.getArgumentTypes().length == 0 && name.equals("<init>"))
            hasNoArgsConstructor = true;
        //This isn't a method we want to weave, so just get the default visitor
        methodVisitorToReturn = cv.visitMethod(access, name, desc, signature, exceptions);
    }
    LOGGER.debug(Constants.LOG_EXIT, "visitMethod", methodVisitorToReturn);
    return methodVisitorToReturn;
}
Also used : AdviceAdapter(org.objectweb.asm.commons.AdviceAdapter) Method(org.objectweb.asm.commons.Method) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 24 with Method

use of org.objectweb.asm.commons.Method 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 25 with Method

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

the class AbstractWovenProxyMethodAdapter method writeDispatcher.

/**
   * Write out the bytecode instructions necessary to do the dispatch.
   * We know the dispatcher is non-null, and we need a try/catch around the
   * invocation and listener calls.
   */
protected final void writeDispatcher() {
    // Setup locals we will use in the dispatch
    setupLocals();
    //Write the try catch block
    visitTryCatchBlock(beginTry, endTry, endTry, THROWABLE_INAME);
    mark(beginTry);
    //Start dispatching, get the target object and store it
    loadThis();
    getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
    invokeInterface(DISPATCHER_TYPE, new Method("call", OBJECT_TYPE, NO_ARGS));
    storeLocal(dispatchTarget);
    //Pre-invoke, invoke, post-invoke, return
    writePreInvoke();
    //Start the real method
    push(true);
    storeLocal(inNormalMethod);
    //Dispatch the method and store the result (null for void)
    loadLocal(dispatchTarget);
    checkCast(methodDeclaringType);
    loadArgs();
    if (isMethodDeclaringTypeInterface && !isDefaultMethod) {
        invokeInterface(methodDeclaringType, currentTransformMethod);
    } else {
        invokeVirtual(methodDeclaringType, currentTransformMethod);
    }
    if (isVoid) {
        visitInsn(ACONST_NULL);
    }
    storeLocal(normalResult);
    // finish the real method and post-invoke
    push(false);
    storeLocal(inNormalMethod);
    writePostInvoke();
    //Return, with the return value if necessary
    if (!!!isVoid) {
        loadLocal(normalResult);
    }
    returnValue();
    //End of our try, start of our catch
    mark(endTry);
    writeMethodCatchHandler();
}
Also used : Method(org.objectweb.asm.commons.Method)

Aggregations

Method (org.objectweb.asm.commons.Method)32 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)24 Type (org.objectweb.asm.Type)16 Label (org.objectweb.asm.Label)8 ClassWriter (org.objectweb.asm.ClassWriter)7 MethodVisitor (org.objectweb.asm.MethodVisitor)7 IOException (java.io.IOException)6 ClassReader (org.objectweb.asm.ClassReader)5 Schema (co.cask.cdap.api.data.schema.Schema)4 Set (java.util.Set)3 ClassVisitor (org.objectweb.asm.ClassVisitor)3 TypeToken (com.google.common.reflect.TypeToken)2 InvocationHandler (java.lang.reflect.InvocationHandler)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 Sets (com.google.common.collect.Sets)1 JClassType (com.google.gwt.core.ext.typeinfo.JClassType)1 InterceptorType (com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorType)1 File (java.io.File)1