uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

GVM: GroovyでJavaVMを書いたよ

前置き

さてやっと発売日となりました、私も著者の一人として執筆に参加している「プログラミングGroovy」ですが、ご覧になった方もいらっしゃると思います。

プログラミングGROOVY
プログラミングGROOVY
posted with amazlet at 11.07.06
関谷 和愛 上原 潤二 須江 信洋 中野 靖治
技術評論社
売り上げランキング: 4587

興味がありましたら読んで見てください。Groovy普及の1助になれば幸いです。Javaプログラマであれば読んで損はない本だと思います。

ghello

さて、発売日といえば、昨日は著者の1人である関谷さん(id:ksky)が、#ghelloというイベント(まとめサイトGoogleキャッシュ)を行っていて、これはみんなでGroovyでいろいろな「Hello World表示プログラム」を書いて、Twitterで#ghelloタグつけて発言する、というもので、なかなか盛り上りました。私も及ばずながら2、3個ツィートして見ました。2番目の「ぉうききぐじぐこきぅ」というのがちょっと狂気入ってそうな感じでお気に入りです。



良い企画だったと思います。ただ、Twitterなので140文字(しかもハッシュタグと次の人指名含めて)制限があり、これが予想外に厳しくて、ストレスが溜る溜る。

GVM: JVM Written in Groovy

なので、カッとなって、文字数制限なしで作ってみました*1。方針としてはGroovyでJava VMを書いてその上でHello Worldを表示させるJavaコード(コンパイルしたクラスファイル)を動作させる。

コードはgistに公開しましたのでリンクしておきます。本体は長いのでこのエントリには末尾に貼っておきます。

以下は実行例です。

$ cat Hello.java
package sample;
public class Hello {
    public static void main(String[] args){
        Hello h = new Hello();
        h.hello();
        System.out.println(h.plus(1,2));
        for (int i=0; i<10; i++) {
            System.out.print("i=");
            System.out.println(i);
        }
    }
    void hello() {
        System.out.println("Hello World");
    }
    int plus(int i, int j) {
        return i+j;
    }
}
$ mkdir classes
$ javac -d ./classes Hello.java
$ groovy ./gvm.groovy -cp classes sample.Hello
Hello World
3
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9

$ groovy ./gvm.groovy -h
usage: groovy gvm.groovy <class FQCN>
 -cp,--classpath <arg>   classpath
 -demo,--demo            demo
 -h,--help               usage
 -v,--verbose            verbose

デモモード(-demo)もあるので、Javaソースを作ったりjavacしなくてもgvm.groovy単体で実行することができます。

クラスファイルの読み込みとクラス構造やバイトコードの保持については、asmにすべて任せて*2さぼっています。asmはGroovyに組みこまれているバイトコード操作用のライブラリです。Groovy自体がasmによるバイトコード生成に依存して動作しています。

機能的には、足し算はできるが掛け算は(サンプルコードに含まれてないので)実装してないとか、読み込めるクラスは1つでディレクトリのみからでjarは対象外とか、そんな極小な感じです。

Java VMは前から一度は実装してみたいなと思ってて、Groovyなら短時間でできるだろうと思ってやってみました。確かにわりと簡単にはできたのですが*3、適当に作りすぎたのであんまり勉強にはならなったorz。

工夫としては、asmのバイトコード命令をあらわすクラス群(*InsnNode)にmetaClassで「.eval()」メソッドを注入しているところで、これによってコード量が劇的に削減され、単純化されてるんじゃないかと思います。一般に、JavaのクラスライブラリやAPIと連携したりカスタマイズしたりして動くコードを書くのは、Groovyの右に出るものは無いわけです。

Groovyの書き易さは、あらためて本当に体感しました。いやこれはほんとに凄い技術です。Javaで書く気には到底ならないなあ。

Groovy Rocks!

gvm.groovyコード

*1:というのはウソで、半分ぐらい正月につくって放置してましたのを一区切りつけただけです。

*2:asmだとクラスファイルフォーマットの汚いところ(コンスタントプールでlong値は2エントリ取る)とか見えなくなるので逆に味けない。

*3:開発工数は子育てしながらで合計3〜4日ぐらい。