Search in sources :

Example 1 with MethodVisitor

use of org.apache.xbean.asm5.MethodVisitor in project jodd by oblac.

the class ProxettaClassBuilder method makeProxyConstructor.

/**
	 * Creates init method that simply calls all advice constructor methods in correct order.
	 * This created init method is called from each destination's constructor.
	 */
protected void makeProxyConstructor() {
    MethodVisitor mv = wd.dest.visitMethod(AsmUtil.ACC_PRIVATE | AsmUtil.ACC_FINAL, initMethodName, DESC_VOID, null, null);
    mv.visitCode();
    if (wd.adviceInits != null) {
        for (String name : wd.adviceInits) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, wd.thisReference, name, DESC_VOID, false);
        }
    }
    mv.visitInsn(RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}
Also used : MethodVisitor(jodd.asm5.MethodVisitor)

Example 2 with MethodVisitor

use of org.apache.xbean.asm5.MethodVisitor in project jodd by oblac.

the class ProxettaMethodBuilder method createProxyMethod.

/**
	 * Creates proxy methods over target method, For each matched proxy, new proxy method is created
	 * by taking advice bytecode and replaces usages of {@link jodd.proxetta.ProxyTarget}.
	 * <p>
	 * Invocation chain example: {@code name -> name$p0 -> name$p1 -> name$p4 -> super}.
	 */
public void createProxyMethod(final TargetMethodData td) {
    final ProxyAspectData aspectData = td.getProxyData();
    int access = td.msign.getAccessFlags();
    access &= ~ACC_NATIVE;
    access &= ~ACC_ABSTRACT;
    access = ProxettaAsmUtil.makePrivateFinalAccess(access);
    final MethodVisitor mv = wd.dest.visitMethod(access, td.methodName(), td.msign.getDescription(), null, null);
    mv.visitCode();
    //*** VISIT ADVICE - called for each aspect and each method
    aspectData.getAdviceClassReader().accept(new EmptyClassVisitor() {

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            if (!name.equals(executeMethodName)) {
                return null;
            }
            return new HistoryMethodAdapter(mv) {

                @Override
                public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                    if (owner.equals(aspectData.adviceReference)) {
                        // [F5]
                        owner = wd.thisReference;
                        name = adviceFieldName(name, aspectData.aspectIndex);
                    }
                    super.visitFieldInsn(opcode, owner, name, desc);
                }

                @Override
                public void visitVarInsn(int opcode, int var) {
                    var += (var == 0 ? 0 : td.msign.getAllArgumentsSize());
                    if (proxyInfoRequested) {
                        proxyInfoRequested = false;
                        if (opcode == ASTORE) {
                            ProxyTargetReplacement.info(mv, td.msign, var);
                        }
                    }
                    // [F1]
                    super.visitVarInsn(opcode, var);
                }

                @Override
                public void visitIincInsn(int var, int increment) {
                    var += (var == 0 ? 0 : td.msign.getAllArgumentsSize());
                    // [F1]
                    super.visitIincInsn(var, increment);
                }

                @Override
                public void visitInsn(int opcode) {
                    if (opcode == ARETURN) {
                        visitReturn(mv, td.msign, true);
                        return;
                    }
                    if (traceNext) {
                        if ((opcode == POP) || (opcode == POP2)) {
                            // [F3] - invoke invoked without assignment
                            return;
                        }
                    }
                    super.visitInsn(opcode);
                }

                @SuppressWarnings({ "ParameterNameDiffersFromOverriddenParameter" })
                @Override
                public void visitMethodInsn(int opcode, String string, String mname, String mdesc, boolean isInterface) {
                    if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE) || (opcode == INVOKESPECIAL)) {
                        if (string.equals(aspectData.adviceReference)) {
                            string = wd.thisReference;
                            mname = adviceMethodName(mname, aspectData.aspectIndex);
                        }
                    } else if (opcode == INVOKESTATIC) {
                        if (string.equals(aspectData.adviceReference)) {
                            string = wd.thisReference;
                            mname = adviceMethodName(mname, aspectData.aspectIndex);
                        } else if (string.endsWith('/' + TARGET_CLASS_NAME)) {
                            if (isInvokeMethod(mname, mdesc)) {
                                // [R7]
                                if (td.isLastMethodInChain()) {
                                    if (!wd.isWrapper()) {
                                        // PROXY
                                        loadSpecialMethodArguments(mv, td.msign);
                                        mv.visitMethodInsn(INVOKESPECIAL, wd.superReference, td.msign.getMethodName(), td.msign.getDescription(), isInterface);
                                    } else {
                                        // WRAPPER
                                        mv.visitVarInsn(ALOAD, 0);
                                        mv.visitFieldInsn(GETFIELD, wd.thisReference, wd.wrapperRef, wd.wrapperType);
                                        loadVirtualMethodArguments(mv, td.msign);
                                        if (wd.wrapInterface) {
                                            mv.visitMethodInsn(INVOKEINTERFACE, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), td.msign.getMethodName(), td.msign.getDescription(), true);
                                        } else {
                                            mv.visitMethodInsn(INVOKEVIRTUAL, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), td.msign.getMethodName(), td.msign.getDescription(), isInterface);
                                        }
                                    }
                                    // [F4]
                                    prepareReturnValue(mv, td.msign, aspectData.maxLocalVarOffset);
                                    traceNext = true;
                                } else {
                                    // calls next proxy method
                                    loadSpecialMethodArguments(mv, td.msign);
                                    mv.visitMethodInsn(INVOKESPECIAL, wd.thisReference, td.nextMethodName(), td.msign.getDescription(), isInterface);
                                    visitReturn(mv, td.msign, false);
                                }
                                return;
                            }
                            if (isArgumentsCountMethod(mname, mdesc)) {
                                // [R2]
                                ProxyTargetReplacement.argumentsCount(mv, td.msign);
                                return;
                            }
                            if (isArgumentTypeMethod(mname, mdesc)) {
                                // [R3]
                                int argIndex = this.getArgumentIndex();
                                ProxyTargetReplacement.argumentType(mv, td.msign, argIndex);
                                return;
                            }
                            if (isArgumentMethod(mname, mdesc)) {
                                // [R4]
                                int argIndex = this.getArgumentIndex();
                                ProxyTargetReplacement.argument(mv, td.msign, argIndex);
                                return;
                            }
                            if (isSetArgumentMethod(mname, mdesc)) {
                                // [R5]
                                int argIndex = this.getArgumentIndex();
                                checkArgumentIndex(td.msign, argIndex);
                                mv.visitInsn(POP);
                                storeMethodArgumentFromObject(mv, td.msign, argIndex);
                                return;
                            }
                            if (isCreateArgumentsArrayMethod(mname, mdesc)) {
                                // [R6]
                                ProxyTargetReplacement.createArgumentsArray(mv, td.msign);
                                return;
                            }
                            if (isCreateArgumentsClassArrayMethod(mname, mdesc)) {
                                // [R11]
                                ProxyTargetReplacement.createArgumentsClassArray(mv, td.msign);
                                return;
                            }
                            if (isTargetMethod(mname, mdesc)) {
                                // [R9.1]
                                mv.visitVarInsn(ALOAD, 0);
                                return;
                            }
                            if (isTargetClassMethod(mname, mdesc)) {
                                // [R9]
                                ProxyTargetReplacement.targetClass(mv, td.msign);
                                //ProxyTargetReplacement.targetClass(mv, wd.superReference);
                                return;
                            }
                            if (isTargetMethodNameMethod(mname, mdesc)) {
                                // [R10]
                                ProxyTargetReplacement.targetMethodName(mv, td.msign);
                                return;
                            }
                            if (isTargetMethodSignatureMethod(mname, mdesc)) {
                                ProxyTargetReplacement.targetMethodSignature(mv, td.msign);
                                return;
                            }
                            if (isTargetMethodDescriptionMethod(mname, mdesc)) {
                                ProxyTargetReplacement.targetMethodDescription(mv, td.msign);
                                return;
                            }
                            if (isInfoMethod(mname, mdesc)) {
                                // we are NOT replacing info() here! First, we need to figure out
                                // what is the operand for the very next ASTORE instructions
                                // since we need to create an object and store it in this
                                // register - and reuse it, in replacement code.
                                //ProxyTargetReplacement.info(mv, td.msign);
                                proxyInfoRequested = true;
                                return;
                            }
                            if (isReturnTypeMethod(mname, mdesc)) {
                                // [R11]
                                ProxyTargetReplacement.returnType(mv, td.msign);
                                return;
                            }
                            if (isReturnValueMethod(mname, mdesc)) {
                                castToReturnType(mv, td.msign);
                                return;
                            }
                            if (isTargetMethodAnnotationMethod(mname, mdesc)) {
                                String[] args = getLastTwoStringArguments();
                                // pop current two args
                                mv.visitInsn(POP);
                                mv.visitInsn(POP);
                                ProxyTargetReplacement.targetMethodAnnotation(mv, td.msign, args);
                                return;
                            }
                            if (isTargetClassAnnotationMethod(mname, mdesc)) {
                                String[] args = getLastTwoStringArguments();
                                // pop current two args
                                mv.visitInsn(POP);
                                mv.visitInsn(POP);
                                ProxyTargetReplacement.targetClassAnnotation(mv, td.msign.getClassInfo(), args);
                                return;
                            }
                        }
                    }
                    super.visitMethodInsn(opcode, string, mname, mdesc, isInterface);
                }
            };
        }
    }, 0);
}
Also used : EmptyClassVisitor(jodd.asm.EmptyClassVisitor) EmptyMethodVisitor(jodd.asm.EmptyMethodVisitor) MethodVisitor(jodd.asm5.MethodVisitor)

Example 3 with MethodVisitor

use of org.apache.xbean.asm5.MethodVisitor in project tomee by apache.

the class DynamicSubclass method generateBytes.

private static byte[] generateBytes(final Class<?> classToProxy) throws ProxyGenerationException {
    final Map<String, MethodVisitor> visitors = new HashMap<>();
    final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    final String proxyClassFileName = getSubclassName(classToProxy).replace('.', '/');
    final String classFileName = classToProxy.getName().replace('.', '/');
    cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, proxyClassFileName, null, classFileName, null);
    cw.visitSource(classFileName + ".java", null);
    // push InvocationHandler field
    cw.visitField(ACC_FINAL + ACC_PRIVATE, "this$handler", "Ljava/lang/reflect/InvocationHandler;", null, null).visitEnd();
    for (final Constructor<?> constructor : classToProxy.getConstructors()) {
        if (!Modifier.isPublic(constructor.getModifiers())) {
            continue;
        }
        final MethodVisitor mv = visitConstructor(cw, proxyClassFileName, classFileName, constructor);
        visitors.put("<init>" + Type.getConstructorDescriptor(constructor), mv);
    }
    final Map<String, List<Method>> methodMap = new HashMap<>();
    getNonPrivateMethods(classToProxy, methodMap);
    // Iterate over the public methods
    for (final Map.Entry<String, List<Method>> entry : methodMap.entrySet()) {
        for (final Method method : entry.getValue()) {
            if (Modifier.isAbstract(method.getModifiers())) {
                final MethodVisitor visitor = LocalBeanProxyFactory.visit(cw, method, proxyClassFileName, "this$handler");
                visitors.put(method.getName() + Type.getMethodDescriptor(method), visitor);
            }
        }
    }
    copyClassAnnotations(classToProxy, cw);
    copyMethodAnnotations(classToProxy, visitors);
    // This should never be reached, but just in case
    for (final MethodVisitor visitor : visitors.values()) {
        visitor.visitEnd();
    }
    return cw.toByteArray();
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Arrays.asList(java.util.Arrays.asList) List(java.util.List) Method(java.lang.reflect.Method) HashMap(java.util.HashMap) Map(java.util.Map) ClassWriter(org.apache.xbean.asm5.ClassWriter) MethodVisitor(org.apache.xbean.asm5.MethodVisitor)

Example 4 with MethodVisitor

use of org.apache.xbean.asm5.MethodVisitor in project component-runtime by Talend.

the class ProxyGenerator method createConstructor.

private String createConstructor(final ClassWriter cw, final Class<?> classToProxy, final String classFileName, final String proxyClassFileName, final Constructor<?> constructor, final boolean withInterceptors) {
    try {
        Constructor superDefaultCt;
        String parentClassFileName;
        String[] exceptions = null;
        if (classToProxy.isInterface()) {
            parentClassFileName = Type.getInternalName(Object.class);
            superDefaultCt = Object.class.getConstructor();
        } else {
            parentClassFileName = classFileName;
            if (constructor == null) {
                superDefaultCt = classToProxy.getConstructor();
            } else {
                superDefaultCt = constructor;
                Class<?>[] exceptionTypes = constructor.getExceptionTypes();
                exceptions = exceptionTypes.length == 0 ? null : new String[exceptionTypes.length];
                for (int i = 0; i < exceptionTypes.length; i++) {
                    exceptions[i] = Type.getInternalName(exceptionTypes[i]);
                }
            }
        }
        final String descriptor = Type.getConstructorDescriptor(superDefaultCt);
        final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", descriptor, null, exceptions);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        if (constructor != null) {
            for (int i = 1; i <= constructor.getParameterTypes().length; i++) {
                mv.visitVarInsn(ALOAD, i);
            }
        }
        mv.visitMethodInsn(INVOKESPECIAL, parentClassFileName, "<init>", descriptor, false);
        if (withInterceptors) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitInsn(ACONST_NULL);
            mv.visitFieldInsn(PUTFIELD, proxyClassFileName, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class));
        }
        mv.visitInsn(RETURN);
        mv.visitMaxs(-1, -1);
        mv.visitEnd();
        return parentClassFileName;
    } catch (final NoSuchMethodException e) {
        throw new IllegalStateException(e);
    }
}
Also used : InterceptorHandler(org.talend.sdk.component.api.service.interceptor.InterceptorHandler) Constructor(java.lang.reflect.Constructor) AllArgsConstructor(lombok.AllArgsConstructor) MethodVisitor(org.apache.xbean.asm6.MethodVisitor)

Example 5 with MethodVisitor

use of org.apache.xbean.asm5.MethodVisitor in project component-runtime by Talend.

the class ProxyGenerator method delegateMethod.

private void delegateMethod(final ClassWriter cw, final Method method, final String proxyClassFileName, final int methodIndex) {
    final Class<?> returnType = method.getReturnType();
    final Class<?>[] parameterTypes = method.getParameterTypes();
    final Class<?>[] exceptionTypes = method.getExceptionTypes();
    final int modifiers = method.getModifiers();
    if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) {
        throw new IllegalStateException("It's not possible to proxy a final or static method: " + method.getDeclaringClass().getName() + " " + method.getName());
    }
    // push the method definition
    int modifier = modifiers & (ACC_PUBLIC | ACC_PROTECTED | ACC_VARARGS);
    MethodVisitor mv = cw.visitMethod(modifier, method.getName(), Type.getMethodDescriptor(method), null, null);
    mv.visitCode();
    // push try/catch block, to catch declared exceptions, and to catch java.lang.Throwable
    final Label l0 = new Label();
    final Label l1 = new Label();
    final Label l2 = new Label();
    if (exceptionTypes.length > 0) {
        mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException");
    }
    // push try code
    mv.visitLabel(l0);
    final String classNameToOverride = method.getDeclaringClass().getName().replace('.', '/');
    mv.visitLdcInsn(Type.getType("L" + classNameToOverride + ";"));
    // the following code generates the bytecode for this line of Java:
    // Method method = <proxy>.class.getMethod("add", new Class[] { <array of function argument classes> });
    // get the method name to invoke, and push to stack
    mv.visitLdcInsn(method.getName());
    // create the Class[]
    createArrayDefinition(mv, parameterTypes.length, Class.class);
    int length = 1;
    // push parameters into array
    for (int i = 0; i < parameterTypes.length; i++) {
        // keep copy of array on stack
        mv.visitInsn(DUP);
        Class<?> parameterType = parameterTypes[i];
        // push number onto stack
        pushIntOntoStack(mv, i);
        if (parameterType.isPrimitive()) {
            String wrapperType = getWrapperType(parameterType);
            mv.visitFieldInsn(GETSTATIC, wrapperType, "TYPE", "Ljava/lang/Class;");
        } else {
            mv.visitLdcInsn(Type.getType(parameterType));
        }
        mv.visitInsn(AASTORE);
        if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType)) {
            length += 2;
        } else {
            length++;
        }
    }
    // the following code generates bytecode equivalent to:
    // return ((<returntype>) invocationHandler.invoke(this, {methodIndex}, new Object[] { <function arguments
    // }))[.<primitive>Value()];
    final Label l4 = new Label();
    mv.visitLabel(l4);
    mv.visitVarInsn(ALOAD, 0);
    // get the invocationHandler field from this class
    mv.visitFieldInsn(GETFIELD, proxyClassFileName, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class));
    // add the Method from the static array as first parameter
    mv.visitFieldInsn(GETSTATIC, proxyClassFileName, FIELD_INTERCEPTED_METHODS, Type.getDescriptor(Method[].class));
    // push the methodIndex of the current method
    if (methodIndex < 128) {
        mv.visitIntInsn(BIPUSH, methodIndex);
    } else if (methodIndex < 32267) {
        // for methods > 127 we need to push a short number as index
        mv.visitIntInsn(SIPUSH, methodIndex);
    } else {
        throw new IllegalStateException("Sorry, we only support Classes with 2^15 methods...");
    }
    // and now load the Method from the array
    mv.visitInsn(AALOAD);
    // prepare the parameter array as Object[] and store it on the stack
    pushMethodParameterArray(mv, parameterTypes);
    // invoke the invocationHandler
    mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(InterceptorHandler.class), "invoke", "(Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true);
    // cast the result
    mv.visitTypeInsn(CHECKCAST, getCastType(returnType));
    if (returnType.isPrimitive() && (!Void.TYPE.equals(returnType))) {
        // get the primitive value
        mv.visitMethodInsn(INVOKEVIRTUAL, getWrapperType(returnType), getPrimitiveMethod(returnType), "()" + Type.getDescriptor(returnType), false);
    }
    // push return
    mv.visitLabel(l1);
    if (!Void.TYPE.equals(returnType)) {
        mv.visitInsn(getReturnInsn(returnType));
    } else {
        mv.visitInsn(POP);
        mv.visitInsn(RETURN);
    }
    // catch InvocationTargetException
    if (exceptionTypes.length > 0) {
        mv.visitLabel(l2);
        mv.visitVarInsn(ASTORE, length);
        Label l5 = new Label();
        mv.visitLabel(l5);
        for (int i = 0; i < exceptionTypes.length; i++) {
            Class<?> exceptionType = exceptionTypes[i];
            mv.visitLdcInsn(Type.getType("L" + exceptionType.getCanonicalName().replace('.', '/') + ";"));
            mv.visitVarInsn(ALOAD, length);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false);
            final Label l6 = new Label();
            mv.visitJumpInsn(IFEQ, l6);
            final Label l7 = new Label();
            mv.visitLabel(l7);
            mv.visitVarInsn(ALOAD, length);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
            mv.visitTypeInsn(CHECKCAST, getCastType(exceptionType));
            mv.visitInsn(ATHROW);
            mv.visitLabel(l6);
            if (i == (exceptionTypes.length - 1)) {
                mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
                mv.visitInsn(DUP);
                mv.visitVarInsn(ALOAD, length);
                mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V", false);
                mv.visitInsn(ATHROW);
            }
        }
    }
    // finish this method
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}
Also used : InterceptorHandler(org.talend.sdk.component.api.service.interceptor.InterceptorHandler) Label(org.apache.xbean.asm6.Label) MethodVisitor(org.apache.xbean.asm6.MethodVisitor)

Aggregations

MethodVisitor (org.apache.xbean.asm9.MethodVisitor)30 MethodVisitor (jodd.asm5.MethodVisitor)6 MethodVisitor (org.apache.xbean.asm6.MethodVisitor)6 ClassWriter (org.apache.xbean.asm9.ClassWriter)6 Method (java.lang.reflect.Method)5 Label (org.apache.xbean.asm9.Label)5 Type (org.apache.xbean.asm9.Type)3 ArrayList (java.util.ArrayList)2 Arrays.asList (java.util.Arrays.asList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 ZipEntry (java.util.zip.ZipEntry)2 EmptyClassVisitor (jodd.asm.EmptyClassVisitor)2 EmptyMethodVisitor (jodd.asm.EmptyMethodVisitor)2 AnnotationVisitor (org.apache.xbean.asm6.AnnotationVisitor)2 ClassWriter (org.apache.xbean.asm6.ClassWriter)2 AnnotationVisitor (org.apache.xbean.asm9.AnnotationVisitor)2 InterceptorHandler (org.talend.sdk.component.api.service.interceptor.InterceptorHandler)2 IOException (java.io.IOException)1