在字节码中确定哪里是super()方法调用,所有构造函数必须在JVM上执行 [英] Determining in the bytecode where is the super() method call all constructors must do on the JVM
问题描述
我想知道在分析构造函数的字节码时是否有一种明显而快速的方法,以确定 super()
代码的结束位置。
I was wondering if there's an obvious and quick way of when analyzing a constructor's bytecode, to determine where the super()
code ends in.
更具体地说,与Java形成鲜明对比的是,构造函数中对任何 super()
构造函数方法的调用是可选的(或者更确切地说) ,当不存在时 - 隐式),在字节码世界中总是需要它。
More concretely, and in sharp contrast to Java, where a call in the constructor to any super()
constructor method is optional (or rather, when not present -- implicit), in the bytecode world it is always needed.
出于黑魔法的目的,我需要通过字节码分析和最简单的方法知道, INVOKESPECIAL
调用对应于Java世界的 super()
调用。
For black magic purposes I'm in need of knowing just by bytecode analysis and by the simplest method available, what's the INVOKESPECIAL
call that corresponds to the Java world's super()
call.
我会留下你的一个简单的例子:
I'll leave you here with a hard example:
public static class A {
public A(Object o, Object b) {
}
}
public static class B extends A {
public B() {
//the below super is in bold just to signal that's the one
//I'm looking for
SUPER(new A(new Object(), new Integer(2)), new Integer(1));
System.out.println(new A(new Object(), new Integer(2)));
}
}
带有相应的字节码:
with the corresponding bytecode:
推荐答案
实际上,字节码构造函数的规则比Java的规则要宽松得多。
Actually, the rules for bytecode constructors are much more lax than Java's rules.
唯一的规则是必须在任何正常返回的路径上调用一个构造函数如果构造函数调用抛出异常,那么你也必须抛出异常。
The only rule is that exactly one constructor must be called on any path that returns normally and if a constructor call throws an exception, then you must throw an exception too.
除此之外,这意味着构造函数可能包含对其他构造函数的多次调用或者没有
Among other things, this means that a constructor may contain multiple calls to other constructors or none at all.
无论如何,确定给定调用特殊
调用是否正在初始化当前对象的唯一保证方法是进行数据流分析,因为可以初始化同一类的其他对象,这会混淆一个天真的探测器。
Anyway, the only guaranteed way to determine whether a given invokespecial
call is initializing the current object is to do a dataflow analysis, since it's possible to initialize other objects of the same class, which would confuse a naive detector.
编辑:这是一个完全有效的类(使用Krakatau汇编语法)的示例,显示了您可能遇到的一些问题。除此之外,它还调用了同一个类中的其他构造函数,构造函数的递归调用,以及在构造函数中构造同一个类的其他对象。
Here is an example of a perfectly valid class (using the Krakatau assembler syntax), showing some of the issues you could run into. Among other things, it has calls to other constructors in the same class, recursive invocation of constructors, and constructing other objects of the same class inside the constructor.
.class public ctors
.super java/lang/Object
; A normal constructor
.method public <init> : ()V
.limit locals 1
.limit stack 1
aload_0
invokespecial java/lang/Object <init> ()V
return
.end method
; A weird constructor
.method public <init> : (I)V
.limit locals 2
.limit stack 5
iload_1
ifne LREST
aload_0
invokespecial ctors <init> ()V
return
LREST:
aload_0
new ctors
iinc 1 -1
iload_1
LFAKE_START:
invokespecial ctors <init> (I)V
LFAKE_END:
iconst_0
invokespecial ctors <init> (I)V
return
.catch [0] from LFAKE_START to LFAKE_END using LCATCH
LCATCH:
aload_0
invokespecial java/lang/Object <init> ()V
return
.end method
.method public static main : ([Ljava/lang/String;)V
.limit locals 1
.limit stack 2
new ctors
iconst_5
invokespecial ctors <init> (I)V
return
.end method
这篇关于在字节码中确定哪里是super()方法调用,所有构造函数必须在JVM上执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!