我正在尝试在java字节码中进行一些错误处理。我首先尝试实现一些类似catch的子例程,在那里我将检查错误情况,并跳转到相应的子例程,有点像:
iconst_1
iconst_0
dup
ifeq calldiverr
goto enddivtest
calldiverr:
jsr divError
enddivtest:
idiv
...More instructions...
divError:
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Oh dear you divided by 0!"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
上面的问题是当我有多个跳转到这个子程序的指令时,运行字节码时会收到一条错误信息,说堆栈高度不一致。
也许使用例外是解决这个问题的最好方法吗?
通过一些谷歌搜索我发现你可以创建Exception类的实例并用以下内容初始化它们:
new java/lang/Exception
dup
ldc "exception message!"
invokespecial java/lang/Exception/<init>(Ljava/lang/String;)V
我还发现你可以用athrow
抛出它们,这似乎没问题。
然而令我感到困惑的是如何抓住异常。似乎有一个神奇的“异常表”将异常的抛出和捕获粘在一起,但我不知道如何从头开始编写字节码(以及使用Jasmin进行汇编)时定义其中一个。有人可以告诉我创建异常表的秘诀吗?并且可能给我一个与jasmin汇编的异常处理示例?
答案 0 :(得分:2)
最后,我提出了一个比jsr
更好的解决方案 - 在Jasmin中使用.method
定义一个方法。一旦检测到错误,我就用invokestatic
来调用我的错误处理程序。
对于那些寻找实际异常处理的人 - 我认为在Jasmin中定义异常表可能是使用.catch
完成的,但我没有调查它,因为方法定义解决了我的问题。
编辑:
我最后必须查看.catch
,发现它非常易于使用。它记录在案here。
答案 1 :(得分:0)
首先,它值得指出版本51.0中的类文件可能不包含jsr指令。重复代码或使用方法。
在字节码的每一点,必须知道帧中每个元素的静态类型。每个帧都不是调用堆栈。
一般来说,你不想玩巨大的筹码。将临时存储在局部变量中以保持简单。
如果抛出异常,那么显然该帧可能已经从异常可能抛出的任何地方获取了内容。因此,内容将被丢弃并替换为异常。无论如何,您将无法返回并继续使用框架内容。
答案 2 :(得分:0)
验证jsr
的规则非常复杂,正如Tom所说,操作码已被弃用。所以最好避免。
jsr
上的记忆有点模糊,但是......
(更新)Java字节码验证中有一条规则,即只要两个控制流连接在一起,堆栈深度必须在两个分支上相同。 jsr
子例程从这个规则中被豁免到一个点 - 具有不同堆栈深度的多个异常点可以“到达”相同的jsr
例程,但是堆栈深度的净变化来自jsr
例程后续ret
的条目必须为零(或实际上减1,因为异常原因总是在进入例程时被推送)。
此外,虽然jsr
例程可以“转义”并分支回常规控制流,但如果这样做,则jsr
不会从连接点的堆栈深度规则中免除。这严重限制了您可以执行此操作的情况,因为可能会以不同的堆栈深度输入jsr
例程。
(我毫无疑问仍然有一些错误,但这是我能做的最好的。)
(我不太明白你是如何计划“解决”jsr
例外的问题。)
(另外,Sun使字节码写入更复杂,有4或5(不记得哪个),这使得手动编码字节码几乎不可能。他们这样做是因为他们不知道如何快速进行验证足以击败IBM的验证者,但这是另一回事。)