gpt4 book ai didi

java - 使用 Krakatau 自动填充 StackMapTable

转载 作者:行者123 更新时间:2023-12-02 12:01:09 26 4
gpt4 key购买 nike

我正在使用 Krakatau 从 Jasmin 语法生成字节码。我的 Jasmin 代码是通过三地址代码 (TAC) 形式的中间代码的直接翻译而创建的。我的问题是我无法确定,只能查看 TAC,在翻译跳转语句时我应该将我的 stack 指令放置在其中。

Krakatau 汇编程序的文档说明如下:

The content of a StackMapTable attribute is automatically filled in based on the stack directives in the enclosing code attribute. If this attribute’s contents are nonempty and the attribute isn’t specified explicitly, one will be added implicitly.

但它也说:

Krakatau will not calculate a new stack map for you from bytecode that does not have any stack information. If you want to do this, you should try using ASM.

我对哪种指令以及应该将它们添加到翻译中的位置感到困惑,以便汇编器知道如何隐式添加属性。对此的任何帮助将不胜感激。

例如,我用类似于 Java 的语法编写了这段代码(但不一样,所以我需要使用另一个编译器):

我从编译器前端得到的是左侧的 TAC,我的翻译器生成右侧的 Jasmin 代码(我删除了页眉和页脚,只留下字节码本身,缺少返回指令) :

当我尝试运行它时,我得到如下信息:

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 24
Exception Details:
Location:
Main.main([Ljava/lang/String;)V @16: iflt
Reason:
Expected stackmap frame at this location.
Bytecode:
0x0000000: 1103 e8bc 073a 050f 4814 000a 4a27 2997
0x0000010: 9b00 0819 0503 2752 b1

at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)

我知道发生这种情况是因为它期望在带有标签 L23 的行后面附加一个 .stack 附加 double 对象 [D,但是,正如我之前所说,这示例很简单,我不能总是推断出此类指令的位置。如果 Krakatau 能够通过在封闭代码属性的开头附加一些指令来推断的话,那就太好了。

最佳答案

最简单的方法是完全避免使用堆栈映射。仅当您想使用 51.0+ 版本的功能(即 invokedynamic)时才需要堆栈映射。如果您不使用invokedynamic,则只需将类文件版本设置为50或更低,并且根本不需要堆栈映射。事实上,如果您没有明确指定版本,Krakatau 会将版本默认为 49.0,因此您无需在那里执行任何操作。

如果您使用invokedynamic,事情会变得更加棘手,因为您必须生成堆栈映射。基本规则是,只要可以从前一条指令以外的任何地方访问一条指令,就需要一个堆栈映射条目。 (我认为您还需要死代码的条目,但我没有检查)。

至于实际生成条目,有几种不同类型的堆栈帧,但您不必担心。最简单的方法是每次都使用完整帧。这涉及列出局部变量(“寄存器”)槽和操作数堆栈中每个实时值的当前类型,因此您必须跟踪这些值。

是的,计算和生成所有这些类型信息是一件痛苦的事情,但是您必须为此责怪 Oracle,而不是我。或者,您可以尝试使用 ASM 为您生成堆栈映射,如文档中的建议。

关于java - 使用 Krakatau 自动填充 StackMapTable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47245539/

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