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 .

コンパイルしたら早速動かしてみる。

.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のコード(クラスファイル)をアセンブラレベルで書くことができる。

最後の方法を応用すれば、継続をネイティブにサポートできるかもしれないと思った。