gpt4 book ai didi

java - ASM库中MethodNode的 'visitMethodInsn'方法的实现

转载 作者:行者123 更新时间:2023-12-02 11:05:21 24 4
gpt4 key购买 nike

这是 MethodNode 类的 visitMethodInsn 方法的主体:

  @Override
public void visitMethodInsn(
final int opcode,
final @InternalForm String owner,
final @Identifier String name,
final @MethodDescriptor String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
}

如您所见,如果 asm api 版本低于 5,则字节码不会添加到指令列表中。这背后的原因是什么?

最佳答案

对 Gitlab 上的历史记录进行的一些调查表明,有问题的代码是在 this commit 中添加的。 ,提交消息添加了对接口(interface)上的 invokespecial 和 invokestatic 的支持。

Java 8 引入了在接口(interface)中定义非抽象方法的能力,称为默认方法。在字节码级别,更改的效果是您现在可以通过 invokespecialinvokestatic 指令使用接口(interface)方法和类方法。

在Java 8之前,生成字节码时,只需通过指令即可确定常量池条目的类型:如果操作码为invokeinterface,则生成InterfaceMethod条目,否则生成 Method 条目。在 Java 8 中,这不再可能了,因为 invokespecialinvokestatic 是不明确的,这意味着用户需要能够显式传入该方法是否是接口(interface)方法与否。这意味着他们必须向几乎所有方法 api 添加额外的参数。

但是,他们不想破坏向后兼容性,这意味着他们需要保留具有旧签名的方法(即没有 itf 参数)。这些方法将转发到新方法,对于 invokeinterface 指令,itf 默认为 true,否则为 false,这似乎是一个合理的默认值。这就是您在上面看到的 super 调用所做的事情。我不确定为什么 API < 5 开关在那里,但我怀疑它要么是为了确保向后兼容性,要么是为了打破方法调度方案中的无限循环。

顺便说一句,MethodNode 在大约 8 个月前作为主要代码重组的一部分被删除,因此您不会在最新版本的 ASM 中看到它。

编辑:我发现您对方法委托(delegate)感到困惑。这非常棘手,因为涉及四种不同的方法。

作为引用,以下是涉及的代码:方法节点:

@Deprecated
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, desc));
}

@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
}

然后在父类(super class)中,有

@Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}

public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException(
"INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, desc);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
}

在更改之前,仅存在不带 itf 参数的方法。重载版本是新的。

如果你仔细观察,你会发现所有委托(delegate)的效果是,当 API < 5 时,它最终会调用旧方法,无论你调用这两个方法中的哪一个。如果您调用新方法,它将在委托(delegate)之前验证 itf 参数。当 API >= 5 时,无论您调用这两个方法中的哪一个,它最终都会调用新方法。如果您调用旧方法,它会在委托(delegate)之前为 itf 选择一个默认值。

所以它并不是忽略方法调用,它只是委托(delegate)给正确的实现。

关于java - ASM库中MethodNode的 'visitMethodInsn'方法的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51008535/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com