6

我正在尝试在 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 组装)时如何定义其中一个。有人能告诉我创建异常表的秘密吗?并可能给我一个将与茉莉花组合的异常处理示例?

4

3 回答 3

2

最后,我想出了一个比在 Jasmin 中jsr使用定义方法更好的解决方案。.method一旦我检测到错误,我只是用来invokestatic调用我的错误处理程序。

对于那些寻找实际异常处理的人 - 我认为在 Jasmin 中定义异常表可以使用 完成.catch,但我没有研究它,因为方法定义解决了我的问题。

编辑:

我确实不得不看.catch最后,发现它真的很容易使用。它记录在这里

于 2011-12-13T17:22:29.057 回答
0

首先值得指出的是 51.0 版的类文件可能不包含 jsr 指令。重复代码或使用方法。

在字节码的每一点,帧中每个元素的静态类型都必须是已知的。每一帧都不是一个调用栈。

通常你不想玩大筹码。将临时变量存储在局部变量中以保持简单。

如果抛出异常,那么显然该框架可能包含来自异常可能抛出的任何地方的内容。所以内容被丢弃并被异常替换。无论如何,您将无法返回并继续使用框架内容。

于 2011-12-12T23:32:58.973 回答
0

验证规则jsr非常复杂,正如 Tom 指出的那样,操作码已被弃用。所以最好避免。

我的记忆jsr有点模糊,但是...

(已更新)Java 字节码验证中有一条规则,即无论两个控制流连接在一起,两个分支的堆栈深度必须相同。 jsr子例程不受此规则的约束——具有不同堆栈深度的多个异常点可以“到达”同一个jsr例程,但从jsr例程进入到后续的堆栈深度的净变化ret必须为零(或实际上是负 1,因为异常原因总是在进入例程时被推送)。

此外,虽然jsr例程可以“逃逸”并分支回常规控制流,但如果这样做,jsr则不能免除连接点的堆栈深度规则。这严重限制了您可以执行此操作的情况,因为jsr可能会以不同的堆栈深度进入例程。

(毫无疑问,我仍然有一些错误,但这是我能做的最好的。)

(我不太明白你打算如何“解决”你jsr的异常问题。)

(此外,Sun 使用 4 或 5(不记得是哪个)使字节码编写变得更加复杂,这使得手动编码字节码几乎不可能。他们这样做是因为他们不知道如何以足够快的速度进行验证以击败IBM 的验证者,但那是另一回事。)

于 2011-12-13T01:55:33.240 回答