ASM实践

一、 Bytecode instructions

1. 组成

由opcode和arguments两部分组成。
opcode:一个unsigned byte值,标示某条特定的指令;
arguments:定义某条指令的行为,紧跟在opcode后面;
Instruction arguments和Instruction operands:
arguments编译期可见,存储在已编译文件中;
operand来自operand堆栈,仅在运运行期可见。

ASM实践_第1张图片
类型描述符(Type descriptors).png
ASM实践_第2张图片
方法描述符(Method descriptors).png

2. Bytecode instructions分类:

2.1 在local variables 和 operand stack之间转移数据的指令

  • xLOAD:从local variable中读取压入operand stack中;
  • ILOAD: boolean, byte, char, short, or int;
  • LLOAD: long
  • FLOAD: float
  • DLOAD: double
  • ALOAD: 非primitive类型,如object和references。

2.2. 仅操作operand stack的指令

  • Stack: POP, DUP, SWAP
  • Constants: 压入一个常量数据到operand stack中;
    ACONST_NULL:压入null
    ICONST_0:压入0
    FCONST_0 :压入0f
    DCONST_0 :压入0d
    BIPUSH b :压入byte类型b;
    SIPUSH s:压入short类型 s;
    LDC cst: 压入任意的int, float, long, double, String, Class类型cst;
  • Arithmetic and logic :
  • Casts:
  • Objects:
  • Fields:
  • Methods:
  • Arrays:
  • Jumps:
  • Return:

举例:

package pkg;

public class Bean {
    private int f;
    public int getF() {
        return this.f;
    }
    public void setF(int f) {
         this.f = f;
    }
}

getF()方法的指令:

ALOAD 0  //读取local variable 0(this指针)压入operand stack中;
GETFIELD pkg/Bean f I //弹出栈顶元素,并将this.f压入operand stack,
IRETURN //弹出栈顶元素,并把它返回给调用者; 

setF()方法的指令:

ALOAD 0  //将local variable 0 (this指针) 压入operand stack中;
ILOAD 1   // 将local variable 1(参数f)压入到operand stack中;
PUTFIELD pkg/Bean f I  // 弹出上面两个,将f保存到this.f中
RETURN   // 返回至调用者。

默认构造方法:

Bean() { 
    super(); 
}

对应的字节指令:

ALOAD 0 //读取local variable 0(this指针),并压入operand stack中;
INVOKESPECIAL java/lang/Object  ()V  // 从operand stack中弹出栈顶元素,  调用Object的方法;
RETURN //返回至调用者

新的setter方法:

public void checkAndSetF(int f) {
    if (f >= 0) {
        this.f = f;
    } else {
        throw new IllegalArgumentException();
    }
}

对应的字节码指令:

ILOAD 1 //读取local variable 1(参数f),压入operand stack中
IFLT label //弹出栈顶元素、且与0比较,如果Less Than(LT)0,跳转至label标签; 否则的话继续执行下一条指令;
ALOAD 0 //读取local variable 0(this指针),压入operand stack中;
ILOAD 1 //读取local variable 1(参数f),压入operand stack中;
PUTFIELD pkg/Bean f I //弹出上面两个,将参数f保存到this.f中;
GOTO end //无条件跳转至end标签
label:
NEW java/lang/IllegalArgumentException //创建一个Exception对象并压入operand堆栈
DUP //复制operand堆栈的栈顶元素;
INVOKESPECIAL java/lang/IllegalArgumentException  ()V //弹出栈顶
元素并调用Exception的构造方法;
ATHROW //弹出栈顶元素(另外一个副本),作为异常抛出
end:
RETURN //返回至调用者

方法:

public static void sleep(long d) {
    try {
        Thread.sleep(d);
    } catch (InterruptedException e) {
            e.printStackTrace();
    }
}

对应的bytecode指令:


你可能感兴趣的:(ASM实践)