为什么此ASM指令加载10



我使用ASM框架进行测试,我几乎不明白为什么这段代码会产生int值10。有关更多详细信息:该方法返回一个int,我打印回该int。

// This is the complete ASM visit of this method
// ...
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null);
mv.visitCode();
mv.visitIntInsn(Opcodes.BIPUSH, 0);
mv.visitIntInsn(Opcodes.BIPUSH , 0);
mv.visitIntInsn(Opcodes.ISTORE, 2);
mv.visitIntInsn(Opcodes.ILOAD, 1);
mv.visitInsn(Opcodes.IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// ...

反编译器甚至显示了一些奇怪的代码。分解器输出

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class HelloWorld implements Add {
public HelloWorld() {
}
public int add(int var1, int var2) {
boolean var3 = false;
return var1;
}
}
  1. 为什么函数返回10?是虫子吗?这是否引发了一种";未定义行为";,因为变量被加载到";自我;因为被推回?

  2. JVM如何处理变量以及如何分配变量,是基于堆栈的吗?如果是,则aload将只推送数据的重复值

stack before aload: var1 var2 var3
stack after aload_1: var1 var2 var3 var1

还是我完全错了?它看起来有点过度工作,而不是使用注册表。

那个字节码是谁写的?它应该做什么?它实际做的是:

  • (byte) 0作为整数推送到操作数堆栈
  • (byte) 0再次推送到操作数堆栈
  • 从堆栈中弹出最上面的0,并将其作为整数存储在本地变量表的插槽#2中
  • 将integer从局部变量表插槽#1(注意:插槽与以前不同(加载到堆栈中
  • 返回最顶端的堆栈元素作为方法结果

您还需要知道,在本地变量表中

  • #0是被调用方法的this,即对HelloWorld实例的引用
  • #1是第一方法参数CCD_ 9
  • #2是第二方法参数CCD_ 10

因此,如果该方法返回10,则意味着您必须调用var1值为10的方法,因为您返回的插槽#1的内容保持不变。没有任何线索表明您在这里添加了任何像方法名称所暗示的内容。相反,它所做的是将2x0推送到堆栈上,但只使用其中一个,在返回var1之前,无论出于何种原因,都会覆盖var2,正如我所说。然后,反编译器试图理解它,做得很好。


更新:如果您想实现此

public int add(int var1, int var2) {
return var1 + var2;
}

那么你的字节码应该是这样的:

ILOAD 1
ILOAD 2
IADD
IRETURN

最新更新