JasminでJavaアセンブラ入門してみる
今流行のBinary 2.0っぽい話題、というのはちょっと嘘。時間がないと言いつつ何やってるんだろう…。
- インストール
Jasmin Home Pageからjasmin-2.3.zipをダウンロードする。適当な場所に展開してコンパイルする。アーカイブに元々含まれているjasmin.jarはうまく動かない(なんで?)
% mkdir out_cup % javac -source 1.2 -target 1.1 -d out_cup -cp src src/java_cup/Main.java % jar cfm java_cup.jar src/java_cup.mf -C out_cup . % java -jar java_cup.jar -out src/jasmin -nosummary < src/jasmin/parser.cup % java -jar java_cup.jar -out src/java_cup -nosummary < src/java_cup/parser.cup % mkdir out % javac -source 1.2 -target 1.1 -d out -cp src src/Jasmin.java % jar cfm jasmin.jar src/jasmin.mf -C out .
コンパイルしたら早速動かしてみる。
- テストコード1 (Hello World)
.class public myfile .super java/lang/Object ; standard initializer .method public <init>()V aload_0 invokenonvirtual java/lang/Object/<init>()V return .end method ; public static void main(String[]) .method public static main([Ljava/lang/String;)V ; set limits used by this method .limit locals 1 .limit stack 2 ; System.out.println("Hello, JVM World!"); getstatic java/lang/System/out Ljava/io/PrintStream; ldc "Hello, JVM World!" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method
実行結果:
% java -jar jasmin.jar myfile.j % java myfile Hello, JVM World!
- テストコード2 (数値の表示)
.method public static main([Ljava/lang/String;)V ; set limits used by this method .limit locals 3 .limit stack 4 ; String mystr = String.valueOf(100) bipush 100 invokestatic java/lang/String/valueOf(I)Ljava/lang/String; astore_1 ; System.out.println(mystr) getstatic java/lang/System/out Ljava/io/PrintStream; aload_1 invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method
実行結果:
% java -jar jasmin.jar myfile.j % java myfile 100
- テストコード3 (call/cc 1)
.method public static main([Ljava/lang/String;)V ; set limits used by this method .limit locals 10 .limit stack 10 ;; (+ (call/cc (lambda (x) (x 1) 2)) 3) iconst_1 goto callcc_1 iconst_2 callcc_1: iconst_3 iadd istore_0 getstatic java/lang/System/out Ljava/io/PrintStream; iload_0 invokestatic java/lang/String/valueOf(I)Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method
実行結果:
% java -jar jasmin.jar myfile.j % java myfile 4
- テストコード4 (call/cc 2)
.method public static main([Ljava/lang/String;)V .limit locals 10 .limit stack 10 ;; (+ (call/cc (lambda (x) (set! cont x) 1)) 2) ; callcc_test(0, null) iconst_0 aconst_null invokestatic myfile/callcc_test(I[Ljava/lang/Object;)V ; Object[] myarray = new Object[1] iconst_1 anewarray java/lang/Object astore_1 ;; (cont 5) ; myint = new Integer(5) new java/lang/Integer dup iconst_5 invokenonvirtual java/lang/Integer/<init>(I)V astore_2 ; myarray[0] = myint aload_1 iconst_0 aload_2 aastore ; callcc_test(1, myarray) iconst_1 aload_1 invokestatic myfile/callcc_test(I[Ljava/lang/Object;)V return .end method ; static void callcc_test(int cont_id, Object[] args) .method static callcc_test(I[Ljava/lang/Object;)V ; set limits used by this method .limit locals 10 .limit stack 10 iload_0 tableswitch 0 toplevel cont_1 default: no_such_continuation no_such_continuation: ; throw new RuntimeException("No such continuation") new java/lang/RuntimeException dup ldc "No such continuation" invokenonvirtual java/lang/RuntimeException/<init>(Ljava/lang/String;)V athrow cont_1: ; int myint = ((Integer) args[0]).intValue() aload_1 iconst_0 aaload checkcast java/lang/Integer invokevirtual java/lang/Integer/intValue()I goto resume_1 toplevel: iconst_1 resume_1: iconst_2 iadd istore_0 getstatic java/lang/System/out Ljava/io/PrintStream; iload_0 invokestatic java/lang/String/valueOf(I)Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method
実行結果:
% java -jar jasmin.jar myfile.j % java myfile 3 7
- まとめ
Jasminを使うとJava VMのコード(クラスファイル)をアセンブラレベルで書くことができる。
最後の方法を応用すれば、継続をネイティブにサポートできるかもしれないと思った。