2007年9月7日金曜日

try / finally by jsr/ret (~java1.3)

Java 1.3 までは try/finally を jsr バイトコードで実現していた。
一見、トリッキーだがわかってみれば簡潔にできている気もする。
しかし、jsr バイトコードはベリフィケーションが難しく、使用を
避ける方向にある。1.4 以降の javac コンパイラでは極力使用しない
ようになっている。1.5 開発時には jsr をなくしてしまえという意見も
あったとかなかったとか.

次のような簡単な try / finally を 1.3 javac でコンパイルする。

try {
System.out.println("main in try block");
} finally {
System.out.println("main in finally block");
}

結果と、インラインの説明。

Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String main in try block
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: jsr 20
# finally block のある 20 に jump. この際、次のバイトコードオフセット 11 が
# stack に push される。
11: goto 31
# offset 31 に飛び、メソッドからリターンする。

# 0-14 の間で例外が発生した場合、exception table にしたがってここに
# 制御が移る。
14: astore_1
# 例外の参照を loc[1] に保持
15: jsr 20
# jsr で一旦 finally block に飛ぶ。
# ret 2 はここに返ってくる。例外をスローして終わる。
18: aload_1
19: athrow
# stack 上にある jsr が残したアドレスをローカル、ここでは local[2] にコピー。
20: astore_2
21: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #5; //String main in finally block
26: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: ret 2
# loc[2] にあるオフセットにリターンする
31: return
Exception table:
from to target type
0 14 14 any

0 件のコメント: