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 默认,混合
版权声明:本文为q287573145原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。