Search in sources :

Example 1 with EmptyClassVisitor

use of jodd.asm.EmptyClassVisitor 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 2 with EmptyClassVisitor

use of jodd.asm.EmptyClassVisitor in project jodd by oblac.

the class ProxyAspectData method readAdviceData.

// ---------------------------------------------------------------- read
/**
	 * Parse advice class to gather some advice data. Should be called before any advice use.
	 * Must be called only *once* per advice.
	 */
private void readAdviceData() {
    if (ready) {
        return;
    }
    adviceClassReader.accept(new EmptyClassVisitor() {

        /**
			 * Stores advice reference.
			 */
        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            adviceReference = name;
            super.visit(version, access, name, signature, superName, interfaces);
        }

        /**
			 * Prevents advice to have inner classes.
			 */
        @Override
        public void visitInnerClass(String name, String outerName, String innerName, int access) {
            if (outerName.equals(adviceReference)) {
                throw new ProxettaException("Proxetta doesn't allow inner classes in/for advice: " + advice.getName());
            }
            super.visitInnerClass(name, outerName, innerName, access);
        }

        /**
			 * Clones advices fields to destination.
			 */
        @Override
        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
            // [A5]
            wd.dest.visitField(access, adviceFieldName(name, aspectIndex), desc, signature, value);
            return super.visitField(access, name, desc, signature, value);
        }

        /**
			 * Copies advices methods to destination.
			 */
        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            if (name.equals(CLINIT)) {
                // [A6]
                if (!desc.equals(DESC_VOID)) {
                    throw new ProxettaException("Invalid static initialization block description for advice: " + advice.getName());
                }
                name = clinitMethodName + methodDivider + aspectIndex;
                access |= AsmUtil.ACC_PRIVATE | AsmUtil.ACC_FINAL;
                wd.addAdviceClinitMethod(name);
                return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {

                    @Override
                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                    }

                    @Override
                    public void visitLineNumber(int line, Label start) {
                    }

                    @Override
                    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
                        if (opcode == INVOKESTATIC) {
                            if (owner.equals(adviceReference)) {
                                owner = wd.thisReference;
                                name = adviceMethodName(name, aspectIndex);
                            }
                        }
                        super.visitMethodInsn(opcode, owner, name, desc, isInterface);
                    }

                    @Override
                    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                        // [F6]
                        if (owner.equals(adviceReference)) {
                            // [F5]
                            owner = wd.thisReference;
                            name = adviceFieldName(name, aspectIndex);
                        }
                        super.visitFieldInsn(opcode, owner, name, desc);
                    }
                };
            } else if (name.equals(INIT)) {
                // [A7]
                if (!desc.equals(DESC_VOID)) {
                    throw new ProxettaException("Advices can have only default constructors. Invalid advice: " + advice.getName());
                }
                name = initMethodName + methodDivider + aspectIndex;
                access = ProxettaAsmUtil.makePrivateFinalAccess(access);
                wd.addAdviceInitMethod(name);
                return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {

                    @Override
                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                    }

                    @Override
                    public void visitLineNumber(int line, Label start) {
                    }

                    // used to detect and to ignore the first super call()
                    int state;

                    @Override
                    public void visitVarInsn(int opcode, int var) {
                        // [F7]
                        if ((state == 0) && (opcode == ALOAD) && (var == 0)) {
                            state++;
                            return;
                        }
                        super.visitVarInsn(opcode, var);
                    }

                    @Override
                    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
                        if ((state == 1) && (opcode == INVOKESPECIAL)) {
                            state++;
                            return;
                        }
                        if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE)) {
                            if (owner.equals(adviceReference)) {
                                owner = wd.thisReference;
                                name = adviceMethodName(name, aspectIndex);
                            }
                        } else if (opcode == INVOKESTATIC) {
                            if (owner.equals(adviceReference)) {
                                owner = wd.thisReference;
                                name = adviceMethodName(name, aspectIndex);
                            }
                        }
                        super.visitMethodInsn(opcode, owner, name, desc, isInterface);
                    }

                    @Override
                    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                        // [F7]
                        if (owner.equals(adviceReference)) {
                            // [F5]
                            owner = wd.thisReference;
                            name = adviceFieldName(name, aspectIndex);
                        }
                        super.visitFieldInsn(opcode, owner, name, desc);
                    }
                };
            } else // other methods
            if (!name.equals(executeMethodName)) {
                name = adviceMethodName(name, aspectIndex);
                return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {

                    @Override
                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                    }

                    @Override
                    public void visitLineNumber(int line, Label start) {
                    }

                    @Override
                    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
                        if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE)) {
                            if (owner.equals(adviceReference)) {
                                owner = wd.thisReference;
                                name = adviceMethodName(name, aspectIndex);
                            }
                        } else if (opcode == INVOKESTATIC || opcode == INVOKESPECIAL) {
                            if (owner.equals(adviceReference)) {
                                owner = wd.thisReference;
                                name = adviceMethodName(name, aspectIndex);
                            }
                        }
                        super.visitMethodInsn(opcode, owner, name, desc, isInterface);
                    }

                    @Override
                    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                        // replace field references
                        if (owner.equals(adviceReference)) {
                            owner = wd.thisReference;
                            name = adviceFieldName(name, aspectIndex);
                        }
                        super.visitFieldInsn(opcode, owner, name, desc);
                    }
                };
            }
            //return new MethodAdapter(new EmptyMethodVisitor()) {		// toask may we replace this with the following code?
            return new EmptyMethodVisitor() {

                @Override
                public void visitVarInsn(int opcode, int var) {
                    if (isStoreOpcode(opcode)) {
                        if (var > maxLocalVarOffset) {
                            // find max local var offset
                            maxLocalVarOffset = var;
                        }
                    }
                    super.visitVarInsn(opcode, var);
                }
            };
        //					return super.visitMethod(access, name, desc, signature, exceptions);
        }
    }, 0);
    // increment offset by 2 because var on last index may be a dword value
    maxLocalVarOffset += 2;
    ready = true;
}
Also used : ProxettaException(jodd.proxetta.ProxettaException) Label(jodd.asm5.Label) FieldVisitor(jodd.asm5.FieldVisitor) EmptyClassVisitor(jodd.asm.EmptyClassVisitor) EmptyMethodVisitor(jodd.asm.EmptyMethodVisitor) MethodVisitor(jodd.asm5.MethodVisitor) MethodAdapter(jodd.asm.MethodAdapter) EmptyMethodVisitor(jodd.asm.EmptyMethodVisitor)

Aggregations

EmptyClassVisitor (jodd.asm.EmptyClassVisitor)2 EmptyMethodVisitor (jodd.asm.EmptyMethodVisitor)2 MethodVisitor (jodd.asm5.MethodVisitor)2 MethodAdapter (jodd.asm.MethodAdapter)1 FieldVisitor (jodd.asm5.FieldVisitor)1 Label (jodd.asm5.Label)1 ProxettaException (jodd.proxetta.ProxettaException)1