org.yx.asm.ProxyMethodWritor.java Source code

Java tutorial

Introduction

Here is the source code for org.yx.asm.ProxyMethodWritor.java

Source

/**
 * Copyright (C) 2016 - 2017 youtongluan.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.yx.asm;

import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.ATHROW;
import static org.objectweb.asm.Opcodes.DLOAD;
import static org.objectweb.asm.Opcodes.DRETURN;
import static org.objectweb.asm.Opcodes.DSTORE;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.FLOAD;
import static org.objectweb.asm.Opcodes.FRETURN;
import static org.objectweb.asm.Opcodes.FSTORE;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.ICONST_0;
import static org.objectweb.asm.Opcodes.ICONST_1;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.IRETURN;
import static org.objectweb.asm.Opcodes.ISTORE;
import static org.objectweb.asm.Opcodes.LLOAD;
import static org.objectweb.asm.Opcodes.LRETURN;
import static org.objectweb.asm.Opcodes.LSTORE;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.RETURN;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.yx.bean.Box;
import org.yx.conf.AppInfo;

public class ProxyMethodWritor {
    private static int SINGLE = AppInfo.getInt("sumk.aop.single", 1);
    private static int WIDTH = AppInfo.getInt("sumk.aop.width", 2);

    private static int load(MethodVisitor mv, Object type, int frameIndex) {
        if (Opcodes.INTEGER.equals(type)) {
            mv.visitVarInsn(ILOAD, frameIndex);
            return frameIndex + SINGLE;
        }
        if (Opcodes.LONG.equals(type)) {
            mv.visitVarInsn(LLOAD, frameIndex);
            return frameIndex + WIDTH;
        }
        if (Opcodes.FLOAT.equals(type)) {
            mv.visitVarInsn(FLOAD, frameIndex);
            return frameIndex + SINGLE;
        }
        if (Opcodes.DOUBLE.equals(type)) {
            mv.visitVarInsn(DLOAD, frameIndex);
            return frameIndex + WIDTH;
        }
        mv.visitVarInsn(ALOAD, frameIndex);
        return frameIndex + SINGLE;
    }

    private static void store(MethodVisitor mv, Object type, int frameIndex) {
        if (Opcodes.INTEGER.equals(type)) {
            mv.visitVarInsn(ISTORE, frameIndex);
        } else if (Opcodes.LONG.equals(type)) {
            mv.visitVarInsn(LSTORE, frameIndex);
        } else if (Opcodes.FLOAT.equals(type)) {
            mv.visitVarInsn(FSTORE, frameIndex);
        } else if (Opcodes.DOUBLE.equals(type)) {
            mv.visitVarInsn(DSTORE, frameIndex);
        } else {
            mv.visitVarInsn(ASTORE, frameIndex);
        }
    }

    private static void jReturn(MethodVisitor mv, Object type) {
        if (Opcodes.INTEGER.equals(type)) {
            mv.visitInsn(IRETURN);
        } else if (Opcodes.LONG.equals(type)) {
            mv.visitInsn(LRETURN);
        } else if (Opcodes.FLOAT.equals(type)) {
            mv.visitInsn(FRETURN);
        } else if (Opcodes.DOUBLE.equals(type)) {
            mv.visitInsn(DRETURN);
        } else {
            mv.visitInsn(ARETURN);
        }
    }

    /**
     * 
     * @param mv
     * @param argTypes
     * @param frameIndex
     *            ??
     */
    private static void loadArgs(MethodVisitor mv, List<Object> argTypes, int frameIndex) {
        frameIndex++;
        for (Object argType : argTypes) {
            frameIndex = load(mv, argType, frameIndex);
        }
    }

    private static int argLength(List<Object> argTypes) {
        int size = 0;
        for (Object type : argTypes) {
            if (Opcodes.LONG.equals(type) || Opcodes.DOUBLE.equals(type)) {
                size += WIDTH;
            } else {
                size += SINGLE;
            }
        }
        return size;
    }

    private static final String AOPEXCUTOR = "org/yx/common/AopExcutor";

    public static void write(MethodVisitor mv, AsmMethod asmMethod) {
        if (asmMethod.desc.endsWith(")V")) {
            writeVoid(mv, asmMethod);
        } else {
            writeWithReturn(mv, asmMethod);
        }
    }

    public static void writeVoid(MethodVisitor mv, AsmMethod asmMethod) {
        Box db = asmMethod.method.getAnnotation(Box.class);
        if (db == null) {
            return;
        }
        String superowener = Type.getInternalName(asmMethod.superClz);
        String currentClz = asmMethod.currentClz.replace('.', '/');

        List<Object> argTypes = AsmUtils.getImplicitFrame(
                asmMethod.desc.substring(asmMethod.desc.indexOf("(") + 1, asmMethod.desc.indexOf(")")));
        int localVariableIndex = argLength(argTypes);

        mv.visitCode();
        Label l0 = new Label();
        Label l1 = new Label();
        Label l2 = new Label();
        mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
        Label l3 = new Label();
        Label l4 = new Label();
        mv.visitTryCatchBlock(l0, l3, l4, null);
        mv.visitTypeInsn(NEW, AOPEXCUTOR);
        mv.visitInsn(DUP);
        mv.visitInsn(db.embed() ? ICONST_1 : ICONST_0);
        mv.visitMethodInsn(INVOKESPECIAL, AOPEXCUTOR, "<init>", "(Z)V", false);
        mv.visitVarInsn(ASTORE, localVariableIndex + 1);
        mv.visitLabel(l0);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitLdcInsn(db.dbName());
        mv.visitFieldInsn(GETSTATIC, "org/yx/db/DBType", db.dbType().toString(), "Lorg/yx/db/DBType;");
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "begin", "(Ljava/lang/String;Lorg/yx/db/DBType;)V", false);
        mv.visitVarInsn(ALOAD, 0);

        loadArgs(mv, argTypes, 0);
        mv.visitMethodInsn(INVOKESPECIAL, superowener, asmMethod.name, asmMethod.desc, false);

        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "commit", "()V", false);
        mv.visitLabel(l1);
        Label l5 = new Label();
        mv.visitJumpInsn(GOTO, l5);
        mv.visitLabel(l2);

        List<Object> list = new ArrayList<Object>();
        list.add(currentClz);
        list.addAll(argTypes);
        list.add(AOPEXCUTOR);
        Object[] frames = list.toArray(new Object[list.size()]);
        mv.visitFrame(Opcodes.F_FULL, frames.length, frames, 1, new Object[] { "java/lang/Exception" });
        mv.visitVarInsn(ASTORE, localVariableIndex + 2);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitVarInsn(ALOAD, localVariableIndex + 2);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "rollback", "(Ljava/lang/Throwable;)V", false);
        mv.visitLabel(l3);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "close", "()V", false);
        Label l6 = new Label();
        mv.visitJumpInsn(GOTO, l6);
        mv.visitLabel(l4);
        mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" });
        mv.visitVarInsn(ASTORE, localVariableIndex + 3);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "close", "()V", false);
        mv.visitVarInsn(ALOAD, localVariableIndex + 3);
        mv.visitInsn(ATHROW);
        mv.visitLabel(l5);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "close", "()V", false);
        mv.visitLabel(l6);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitInsn(RETURN);
        mv.visitMaxs(Math.max(3, localVariableIndex + 1), 4 + localVariableIndex);
        mv.visitEnd();
    }

    public static void writeWithReturn(MethodVisitor mv, AsmMethod asmMethod) {
        Box db = asmMethod.method.getAnnotation(Box.class);
        if (db == null) {
            return;
        }
        String superowener = Type.getInternalName(asmMethod.superClz);
        String currentClz = asmMethod.currentClz.replace('.', '/');
        List<Object> argTypes = AsmUtils.getImplicitFrame(
                asmMethod.desc.substring(asmMethod.desc.indexOf("(") + 1, asmMethod.desc.indexOf(")")));
        Object returnType = AsmUtils.getImplicitFrame(asmMethod.desc.substring(asmMethod.desc.indexOf(")") + 1))
                .get(0);
        int localVariableIndex = argLength(argTypes);

        mv.visitCode();
        Label l0 = new Label();
        Label l1 = new Label();
        Label l2 = new Label();
        mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
        Label l3 = new Label();
        mv.visitTryCatchBlock(l0, l1, l3, null);
        Label l4 = new Label();
        mv.visitTryCatchBlock(l2, l4, l3, null);
        mv.visitTypeInsn(NEW, AOPEXCUTOR);
        mv.visitInsn(DUP);
        mv.visitInsn(db.embed() ? ICONST_1 : ICONST_0);
        mv.visitMethodInsn(INVOKESPECIAL, AOPEXCUTOR, "<init>", "(Z)V", false);
        mv.visitVarInsn(ASTORE, localVariableIndex + 1);
        mv.visitLabel(l0);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitLdcInsn(db.dbName());
        mv.visitFieldInsn(GETSTATIC, "org/yx/db/DBType", db.dbType().toString(), "Lorg/yx/db/DBType;");
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "begin", "(Ljava/lang/String;Lorg/yx/db/DBType;)V", false);
        mv.visitVarInsn(ALOAD, 0);

        loadArgs(mv, argTypes, 0);
        mv.visitMethodInsn(INVOKESPECIAL, superowener, asmMethod.name, asmMethod.desc, false);
        int methodReturnFrameIndex = localVariableIndex + 2;
        store(mv, returnType, methodReturnFrameIndex);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "commit", "()V", false);

        mv.visitLabel(l1);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "close", "()V", false);
        load(mv, returnType, methodReturnFrameIndex);
        jReturn(mv, returnType);
        mv.visitLabel(l2);

        List<Object> list = new ArrayList<Object>();
        list.add(currentClz);
        list.addAll(argTypes);
        list.add(AOPEXCUTOR);
        Object[] frames = list.toArray(new Object[list.size()]);

        mv.visitFrame(Opcodes.F_FULL, frames.length, frames, 1, new Object[] { "java/lang/Exception" });
        mv.visitVarInsn(ASTORE, localVariableIndex + 2);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitVarInsn(ALOAD, localVariableIndex + 2);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "rollback", "(Ljava/lang/Throwable;)V", false);
        mv.visitLabel(l4);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "close", "()V", false);
        Label l5 = new Label();
        mv.visitJumpInsn(GOTO, l5);
        mv.visitLabel(l3);
        mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" });
        mv.visitVarInsn(ASTORE, localVariableIndex + 3);
        mv.visitVarInsn(ALOAD, localVariableIndex + 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, AOPEXCUTOR, "close", "()V", false);
        mv.visitVarInsn(ALOAD, localVariableIndex + 3);
        mv.visitInsn(ATHROW);
        mv.visitLabel(l5);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitTypeInsn(NEW, "org/yx/exception/SumkException");
        mv.visitInsn(DUP);
        mv.visitLdcInsn(new Integer(-364533425));
        mv.visitLdcInsn("you are locky to see me^_^");
        mv.visitMethodInsn(INVOKESPECIAL, "org/yx/exception/SumkException", "<init>", "(ILjava/lang/String;)V",
                false);
        mv.visitInsn(ATHROW);
        mv.visitMaxs(Math.max(4, localVariableIndex + 1), 4 + localVariableIndex);
        mv.visitEnd();
    }
}