jvm专题系列-11、字节码执行

1、javap

class文件反汇编工具

public class Calc {
    public int calc() {
        int a = 500;
        int b = 200;
        int c = 50;
        return (a + b) / c;
    }
}
​
javap –verbose Calc
​显示如下:
public int calc();
  Code:
   Stack=2, Locals=4, Args_size=1
   0:   sipush  500
   3:   istore_1
   4:   sipush  200
   7:   istore_2
   8:   bipush  50
   10:  istore_3
   11:  iload_1
   12:  iload_2
   13:  iadd
   14:  iload_3
   15:  idiv
   16:  ireturn
}
​

2、简单的字节码执行过程

 

 

 

 

 

 

 

 

 

3、常用的字节码

常量入栈
    aconst_null     null对象入栈
    iconst_m1       int常量-1入栈
    iconst_0        int常量0入栈
    iconst_5
    lconst_1        long常量1入栈
    fconst_1        float 1.0入栈
    dconst_1        double 1.0 入栈
    bipush          8位带符号整数入栈
    sipush          16位带符号整数入栈
    ldc             常量池中的项入栈
​
局部变量压栈
    xload(x为i l f d a)
        分别表示int,long,float,double,object ref
    xload_n(n为0 1 2 3)
    xaload(x为i l f d a b c s)
        分别表示int, long, float, double, obj ref ,byte,char,short
        从数组中取得给定索引的值,将该值压栈
    iaload
        执行前,栈:..., arrayref, index
        它取得arrayref所在数组的index的值,并将值压栈
        执行后,栈:..., value
​
出栈装载入局部变量
    xstore(x为i l f d a)
        出栈,存入局部变量
    xstore_n(n 0 1 2 3)
        出栈,将值存入第n个局部变量
    xastore(x为i l f d a b c s)
        将值存入数组中
    iastore
        执行前,栈:...,arrayref, index, value
        执行后,栈:...
        将value存入arrayref[index]
        
通用栈操作(无类型)
    nop
    pop
        弹出栈顶1个字长
    dup
        复制栈顶1个字长,复制内容压入栈
​
类型转化
    i2l
    i2f
    l2i
    l2f
    l2d
    f2i
    f2d
    d2i
    d2l
    d2f
    i2b
    i2c
    i2s
例如:
    将int转为long
        执行前,栈:..., value
        执行后,栈:...,result.word1,result.word2
        弹出int,扩展为long,并入栈
​
整数运算
    iadd
    ladd
    isub
    lsub
    idiv
    ldiv
    imul
    lmul
    iinc
​
浮点运算
    fadd
    dadd
    fsub
    dsub
    fdiv
    ddiv
    fmul
    dmul
​
对象操作指令
    new
    getfield
    putfield
    getstatic
    putstatic
​
条件控制
    ifeq  如果为0,则跳转
    ifne  如果不为0,则跳转
    iflt   如果小于0 ,则跳转
    ifge  如果大于0,则跳转
    if_icmpeq 如果两个int相同,则跳转
例如:
    ifeq
        参数 byte1,byte2
        value出栈 ,如果栈顶value为0则跳转到(byte1<<8)|byte2
        执行前,栈:...,value
        执行后,栈:...
​
方法调用
    invokevirtual
    invokespecial
    invokestatic
    invokeinterface
    xreturn(x为 i l f d a 或为空)
​

4、使用ASM生成Java字节码

ASM
    Java字节码操作框架
    可以用于修改现有类或者动态产生新类
    用户
        AspectJ
        Clojure
        Ecplise
        spring
        cglib
        hibernate
​

4.1 示例1

 

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES);  
cw.visit(V1_7, ACC_PUBLIC, "Example", null, "java/lang/Object", null);  
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,  null);  
mw.visitVarInsn(ALOAD, 0);  //this 入栈
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");  
mw.visitInsn(RETURN);  
mw.visitMaxs(0, 0);  
mw.visitEnd();  
mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",  "([Ljava/lang/String;)V", null, null);  
mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out",  "Ljava/io/PrintStream;");  
mw.visitLdcInsn("Hello world!");  
mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",  "(Ljava/lang/String;)V");  
mw.visitInsn(RETURN);  
mw.visitMaxs(0,0);  
mw.visitEnd();  
byte[] code = cw.toByteArray();  
AsmHelloWorld loader = new AsmHelloWorld();  
Class exampleClass = loader  
    .defineClass("Example", code, 0, code.length);  
exampleClass.getMethods()[0].invoke(null, new Object[] { null }); 
​

4.2 示例2

模拟实现AOP字节码织入
    - 在函数开始部分或者结束部分嵌入字节码
    - 可用于进行鉴权、日志等
​

 

 

class AddSecurityCheckClassAdapter extends ClassVisitor {
    public AddSecurityCheckClassAdapter( ClassVisitor cv) {
        super(Opcodes.ASM5, cv);
    }
    // 重写 visitMethod,访问到 "operation" 方法时,
    // 给出自定义 MethodVisitor,实际改写方法内容
    public MethodVisitor visitMethod(final int access, final String name, 
        final String desc, final String signature, final String[] exceptions) { 
        MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions);
        MethodVisitor wrappedMv = mv; 
        if (mv != null) { 
            // 对于 "operation" 方法
            if (name.equals("operation")) { 
                // 使用自定义 MethodVisitor,实际改写方法内容
                wrappedMv = new AddSecurityCheckMethodAdapter(mv); 
            } 
        } 
        return wrappedMv; 
    } 
}
​
​
class AddSecurityCheckMethodAdapter extends MethodVisitor { 
     public AddSecurityCheckMethodAdapter(MethodVisitor mv) { 
         super(Opcodes.ASM5,mv); 
     } 
     public void visitCode() { 
         visitMethodInsn(Opcodes.INVOKESTATIC, "geym/jvm/ch10/asm/SecurityChecker", 
            "checkSecurity", "()Z"); 
         super.visitCode();
     } 
}
​
​
public class Generator{ 
     public static void main(String args[]) throws Exception { 
         ClassReader cr = new ClassReader("geym.jvm.ch10.asm.Account"); 
         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); 
         AddSecurityCheckClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw); 
         cr.accept(classAdapter, ClassReader.SKIP_DEBUG); 
         byte[] data = cw.toByteArray(); 
         File file = new File("bin/geym/jvm/ch10/asm/Account.class"); 
         FileOutputStream fout = new FileOutputStream(file); 
         fout.write(data); 
         fout.close(); 
     } 
}
​
控制台输出:
    SecurityChecker.checkSecurity ...
    operation....
​

5、JIT及其相关参数

1)字节码执行性能较差,所以可以对于热点代码编译成机器码再执行,在运行时的编译,叫做JIT Just-In-Time
2)JIT的基本思路是,将热点代码,就是执行比较频繁的代码,编译成机器码。
​

 

 

jvm参数配置
    -Xint
        解释执行
    -Xcomp
        全部编译执行
    -Xmixed
        默认,混合
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步道师就是我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值