Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 类编写器在ASM中计算\u帧_Java_Java Bytecode Asm_Bytecode Manipulation_Jvm Bytecode - Fatal编程技术网

Java 类编写器在ASM中计算\u帧

Java 类编写器在ASM中计算\u帧,java,java-bytecode-asm,bytecode-manipulation,jvm-bytecode,Java,Java Bytecode Asm,Bytecode Manipulation,Jvm Bytecode,我一直试图通过在ASM中使用跳转来理解堆栈映射框架在Java中是如何工作的。我创建了一个简单的方法来尝试一些东西:(用喀拉喀托分解): 而不是 stack Object java/io/PrintStream Object java/lang/StringBuilder Object java/lang/StringBuilder 如我所料 此外,这个类也不会通过验证,因为不能在Top上调用StringBuilder。根据ASM手册,Top指的是一个未初始化的值,但从跳转位置和之前的代

我一直试图通过在ASM中使用跳转来理解堆栈映射框架在Java中是如何工作的。我创建了一个简单的方法来尝试一些东西:(用喀拉喀托分解):

而不是

    stack Object java/io/PrintStream Object java/lang/StringBuilder Object java/lang/StringBuilder
如我所料

此外,这个类也不会通过验证,因为不能在
Top
上调用
StringBuilder
。根据ASM手册,
Top
指的是一个未初始化的值,但从跳转位置和之前的代码来看,它似乎没有在代码中未初始化。我不明白跳伞有什么问题


我插入的跳转是否有什么问题使得类无法计算帧?这可能是ASM的类编写器的错误吗

新java/lang/StringBuilder不创建有效的
StringBuilder
,而是在堆栈映射框中创建一个与
TOP
一起捐赠的单元化对象。在对象构造期间添加跳转指令时使用此值,例如:

new Foo(a ? b : c);
它被翻译成几个goto语句

在对象上调用构造函数时,首先将对象视为
StringBuilder
,即
invokespecial方法java/lang/StringBuilder()V
。JVM不支持在不同的位置初始化此对象,因为验证器只能查看
TOP
类型,该类型不能反映所需的类型,而实际类型是一个统一的
StringBuilder
。您可能会认为JVM应该支持这一点,但这需要更大的数组来包含堆栈映射帧,以反映类型和初始化状态,这可能无法证明Java语言甚至没有使用这种功能

为了说明这一点,请考虑以下情况:

new Foo
dup 
.stack full
    locals 
    stack Top Top 
.end stack
invokespecial Bar <init> ()V 
newfoo
重复
.堆满
当地人
栈顶
.端部堆栈
调用特殊条()V

如果JVM允许对
TOP
类型进行未经检查的初始化,那么这将是有效的,但是显然不应该允许您在
Foo
上调用
Bar
构造函数,因为未初始化的实例是特殊的。考虑到,当<>代码> DUP 引用时,您已经有两个对堆栈中相同实例的引用,您可能执行更多的堆栈操作,或者将引用传递给本地变量,并从那里复制到其他变量或再次推送。尽管如此,在以任何方式使用该引用之前,该引用的目标应该只初始化一次。要验证这一点,必须跟踪对象的标识,以便在对同一对象执行
invokespecial
时,对该对象的所有这些引用都将从未初始化变为已初始化

Java编程语言并没有使用所有的可能性,而是用于法律代码,如
new-Foo(new-Foo(new-Foo(),new-Foo(b?new-Foo(a):new-Foo(b,c))
,在进行分支时,它不应该忘记哪个
Foo
实例已经初始化,哪个没有初始化

因此,每个未初始化的实例堆栈帧条目都绑定到创建它的
new
指令在传输或复制时。只有在对其调用了
invokespecial
之后,指向同一
new
指令的所有引用才会变成声明类的普通实例,并且随后可以与其他类型兼容的条目合并

这意味着像您尝试实现的分支是不可能的。相同类型但由不同的
new
指令创建的两个未初始化实例项是不兼容的。不兼容的类型合并到一个
Top
项中,这基本上是一个不可用的项。如果您不要试图在分支目标中使用该条目,这样ASM在将它们合并到
Top
时就不会有任何错误


请注意,这也意味着不允许任何类型的循环导致堆栈帧具有由同一
new
指令创建的多个未初始化实例。

您似乎有点困惑。如果未初始化对象始终由
Top
类型表示,则在合并时不可用重点,你自己的例子,
newfoo(a?b:c)怎么样
是否应该工作?在这种情况下,验证器将检查应用于堆栈映射帧之外,但如果
新建
指令和构造函数调用之间存在跳转目标,则无法进行验证。在方法调用上也会进行此类附加验证,例如
Foo-Foo=this;Foo.protectedMethod()
无法在方法包之外工作。当您有类似于
new Foo(a?b:c)的代码时;
,在
new
指令和构造函数调用之间有一个分支目标。在字节码级别上,您甚至可以在这两者之间有循环。我刚刚验证了您甚至可以在这两者之间有异常处理。谢谢,每个未初始化的值都绑定到创建它的新语句,这似乎是k我就是。
new Foo(a ? b : c);
new Foo
dup 
.stack full
    locals 
    stack Top Top 
.end stack
invokespecial Bar <init> ()V