Java(DoJa)で例外が発生した行番号が分からない件

PCエンジンエミュレータの移植の作業は大体終わったのですが、
(とりあえずJavaに書き直したという意味では)
まだバグが取りきれていません。
エミュレータを動かしてしばらく放置すると例外が起きるようです…


しかし、そのスタックトレースを見ても、ソースコードのどこで例外が起きたのか分からないのです。
どういうことかというのを、ちょっと簡単なテストコードを書いて、
以下で検証したいと思います。

DoJa(iアプリ)で例外を発生させてみる

DoJa SDK 5.1とEclipse3.1の環境で、以下のようなコードを実行してみます。

package test;

import com.nttdocomo.ui.IApplication;

public class Test extends IApplication {

	public void start() {
		try {
			throw new Exception();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

すると、以下のスタックトレースが出力されます。

java.lang.Exception 
	at test.Test.start(+7)

この「(+7)」って何者でしょうか。
行番号ではありませんね。
これじゃ、スタックトレースを見ても、どこで例外が発生したかわかりません。

じゃあ、バイトコードを見てみよう

classファイルを、javapで逆アセンブルしてみます。

public class test.Test extends com.nttdocomo.ui.IApplication{
public test.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #9; //Method com/nttdocomo/ui/IApplication."":()V
   4:   return

public void start();
  Code:
   0:   new     #16; //class java/lang/Exception
   3:   dup
   4:   invokespecial   #17; //Method java/lang/Exception."":()V
   7:   athrow
   8:   astore_1
   9:   aload_1
   10:  invokevirtual   #20; //Method java/lang/Exception.printStackTrace:()V
   13:  return
  Exception table:
   from   to  target type
     0     8     8   Class java/lang/Exception

}

例外を投げているのは、athrowという命令です。
startメソッドのアドレス7です。
これは、スタックトレースに表示される数値と一致するようです。


つまり、DoJaで作ったアプリを実行したときのスタックトレースの番号は、
行番号ではなく、例外が発生したバイトコードのアドレスを表しているようです。

PC用のJava(J2SDK)でも例外を発生させてみる

PC用のJavaでも同じようなことをやってみます。

class Test {
	public static void main(String[] args)
	{
		try {
			throw new Exception();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

実行結果は、以下のスタックトレースが出力されます。

java.lang.Exception
        at Test.main(Test.java:5)

「Test.java:5」の5は、ソースコードの行番号を示しています。
これなら、例外の発生した位置がわかります。

結局、どういうこと?

DoJa(iアプリ)では、スタックトレースバイトコードアドレスが出力されます。
PC用Javaでは、スタックトレースに行番号が出力されます。

どうしてこうなった!

なぜ、DoJaでは行番号ではなく、バイトコードのアドレスになってしまうのでしょうか。
バイトコードのアドレスなんかを表示してもらっても、正直こまります。


ウェブで調べると、スタックトレースに行番号が表示されない場合、

  1. コンパイラの設定で、デバッグ情報を生成しないようになっている
  2. 最適化が有効になっている
  3. JITによってネイティブコードに変換されている

上の原因があるらしいことがわかりました。


しかし、Eclipseの設定を見ても、デバッグ情報は生成するようになっています。
最適化の設定項目は見当たりませんでしたが…
携帯の場合、JITが無いのでそれは関係なさそうです。


なぜ、DoJaはスタックトレースで行番号が出ないのでしょうか。
デバッグのときに非常にこまるのですが。
ウェブで調べても同じようなことで困っている人は居ないのですが。
私のやり方がおかしいのでしょうか。
それとも、誰もそんなこと気にしないのでしょうか。

どうすればいい?

とりあえずは、どうしてDoJaの場合は、行番号が出力されないのかを調査してみようと思います。
設定などで、行番号が出す方法があるかもしれません。

また、行番号は出力できないということが分かった場合、バイトコードアドレスから、
ソースコードの位置を求める簡単なやり方を考えてみようと思います。

あとは、コードを工夫して、例外が発生したときに、もうちょっとソースコードの情報を埋め込むように
できないかというのも調べてみます。